1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Synaptics TouchPad PS/2 mouse driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * 2003 Dmitry Torokhov <dtor@mail.ru>
6*4882a593Smuzhiyun * Added support for pass-through port. Special thanks to Peter Berg Larsen
7*4882a593Smuzhiyun * for explaining various Synaptics quirks.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * 2003 Peter Osterlund <petero2@telia.com>
10*4882a593Smuzhiyun * Ported to 2.5 input device infrastructure.
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
13*4882a593Smuzhiyun * start merging tpconfig and gpm code to a xfree-input module
14*4882a593Smuzhiyun * adding some changes and extensions (ex. 3rd and 4th button)
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
17*4882a593Smuzhiyun * Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
18*4882a593Smuzhiyun * code for the special synaptics commands (from the tpconfig-source)
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Trademarks are the property of their respective owners.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <linux/module.h>
24*4882a593Smuzhiyun #include <linux/delay.h>
25*4882a593Smuzhiyun #include <linux/dmi.h>
26*4882a593Smuzhiyun #include <linux/input/mt.h>
27*4882a593Smuzhiyun #include <linux/serio.h>
28*4882a593Smuzhiyun #include <linux/libps2.h>
29*4882a593Smuzhiyun #include <linux/rmi.h>
30*4882a593Smuzhiyun #include <linux/i2c.h>
31*4882a593Smuzhiyun #include <linux/slab.h>
32*4882a593Smuzhiyun #include "psmouse.h"
33*4882a593Smuzhiyun #include "synaptics.h"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /*
36*4882a593Smuzhiyun * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
37*4882a593Smuzhiyun * section 2.3.2, which says that they should be valid regardless of the
38*4882a593Smuzhiyun * actual size of the sensor.
39*4882a593Smuzhiyun * Note that newer firmware allows querying device for maximum useable
40*4882a593Smuzhiyun * coordinates.
41*4882a593Smuzhiyun */
42*4882a593Smuzhiyun #define XMIN 0
43*4882a593Smuzhiyun #define XMAX 6143
44*4882a593Smuzhiyun #define YMIN 0
45*4882a593Smuzhiyun #define YMAX 6143
46*4882a593Smuzhiyun #define XMIN_NOMINAL 1472
47*4882a593Smuzhiyun #define XMAX_NOMINAL 5472
48*4882a593Smuzhiyun #define YMIN_NOMINAL 1408
49*4882a593Smuzhiyun #define YMAX_NOMINAL 4448
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* Size in bits of absolute position values reported by the hardware */
52*4882a593Smuzhiyun #define ABS_POS_BITS 13
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun * These values should represent the absolute maximum value that will
56*4882a593Smuzhiyun * be reported for a positive position value. Some Synaptics firmware
57*4882a593Smuzhiyun * uses this value to indicate a finger near the edge of the touchpad
58*4882a593Smuzhiyun * whose precise position cannot be determined.
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * At least one touchpad is known to report positions in excess of this
61*4882a593Smuzhiyun * value which are actually negative values truncated to the 13-bit
62*4882a593Smuzhiyun * reporting range. These values have never been observed to be lower
63*4882a593Smuzhiyun * than 8184 (i.e. -8), so we treat all values greater than 8176 as
64*4882a593Smuzhiyun * negative and any other value as positive.
65*4882a593Smuzhiyun */
66*4882a593Smuzhiyun #define X_MAX_POSITIVE 8176
67*4882a593Smuzhiyun #define Y_MAX_POSITIVE 8176
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* maximum ABS_MT_POSITION displacement (in mm) */
70*4882a593Smuzhiyun #define DMAX 10
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /*****************************************************************************
73*4882a593Smuzhiyun * Stuff we need even when we do not want native Synaptics support
74*4882a593Smuzhiyun ****************************************************************************/
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /*
77*4882a593Smuzhiyun * Set the synaptics touchpad mode byte by special commands
78*4882a593Smuzhiyun */
synaptics_mode_cmd(struct psmouse * psmouse,u8 mode)79*4882a593Smuzhiyun static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun u8 param[1];
82*4882a593Smuzhiyun int error;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun error = ps2_sliced_command(&psmouse->ps2dev, mode);
85*4882a593Smuzhiyun if (error)
86*4882a593Smuzhiyun return error;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun param[0] = SYN_PS_SET_MODE2;
89*4882a593Smuzhiyun error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE);
90*4882a593Smuzhiyun if (error)
91*4882a593Smuzhiyun return error;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
synaptics_detect(struct psmouse * psmouse,bool set_properties)96*4882a593Smuzhiyun int synaptics_detect(struct psmouse *psmouse, bool set_properties)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
99*4882a593Smuzhiyun u8 param[4] = { 0 };
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
102*4882a593Smuzhiyun ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
103*4882a593Smuzhiyun ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
104*4882a593Smuzhiyun ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
105*4882a593Smuzhiyun ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (param[1] != 0x47)
108*4882a593Smuzhiyun return -ENODEV;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun if (set_properties) {
111*4882a593Smuzhiyun psmouse->vendor = "Synaptics";
112*4882a593Smuzhiyun psmouse->name = "TouchPad";
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun return 0;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
synaptics_reset(struct psmouse * psmouse)118*4882a593Smuzhiyun void synaptics_reset(struct psmouse *psmouse)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun /* reset touchpad back to relative mode, gestures enabled */
121*4882a593Smuzhiyun synaptics_mode_cmd(psmouse, 0);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun #if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \
125*4882a593Smuzhiyun defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* This list has been kindly provided by Synaptics. */
128*4882a593Smuzhiyun static const char * const topbuttonpad_pnp_ids[] = {
129*4882a593Smuzhiyun "LEN0017",
130*4882a593Smuzhiyun "LEN0018",
131*4882a593Smuzhiyun "LEN0019",
132*4882a593Smuzhiyun "LEN0023",
133*4882a593Smuzhiyun "LEN002A",
134*4882a593Smuzhiyun "LEN002B",
135*4882a593Smuzhiyun "LEN002C",
136*4882a593Smuzhiyun "LEN002D",
137*4882a593Smuzhiyun "LEN002E",
138*4882a593Smuzhiyun "LEN0033", /* Helix */
139*4882a593Smuzhiyun "LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */
140*4882a593Smuzhiyun "LEN0035", /* X240 */
141*4882a593Smuzhiyun "LEN0036", /* T440 */
142*4882a593Smuzhiyun "LEN0037", /* X1 Carbon 2nd */
143*4882a593Smuzhiyun "LEN0038",
144*4882a593Smuzhiyun "LEN0039", /* T440s */
145*4882a593Smuzhiyun "LEN0041",
146*4882a593Smuzhiyun "LEN0042", /* Yoga */
147*4882a593Smuzhiyun "LEN0045",
148*4882a593Smuzhiyun "LEN0047",
149*4882a593Smuzhiyun "LEN2000", /* S540 */
150*4882a593Smuzhiyun "LEN2001", /* Edge E431 */
151*4882a593Smuzhiyun "LEN2002", /* Edge E531 */
152*4882a593Smuzhiyun "LEN2003",
153*4882a593Smuzhiyun "LEN2004", /* L440 */
154*4882a593Smuzhiyun "LEN2005",
155*4882a593Smuzhiyun "LEN2006", /* Edge E440/E540 */
156*4882a593Smuzhiyun "LEN2007",
157*4882a593Smuzhiyun "LEN2008",
158*4882a593Smuzhiyun "LEN2009",
159*4882a593Smuzhiyun "LEN200A",
160*4882a593Smuzhiyun "LEN200B",
161*4882a593Smuzhiyun NULL
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun static const char * const smbus_pnp_ids[] = {
165*4882a593Smuzhiyun /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */
166*4882a593Smuzhiyun "LEN0048", /* X1 Carbon 3 */
167*4882a593Smuzhiyun "LEN0046", /* X250 */
168*4882a593Smuzhiyun "LEN0049", /* Yoga 11e */
169*4882a593Smuzhiyun "LEN004a", /* W541 */
170*4882a593Smuzhiyun "LEN005b", /* P50 */
171*4882a593Smuzhiyun "LEN005e", /* T560 */
172*4882a593Smuzhiyun "LEN006c", /* T470s */
173*4882a593Smuzhiyun "LEN007a", /* T470s */
174*4882a593Smuzhiyun "LEN0071", /* T480 */
175*4882a593Smuzhiyun "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */
176*4882a593Smuzhiyun "LEN0073", /* X1 Carbon G5 (Elantech) */
177*4882a593Smuzhiyun "LEN0091", /* X1 Carbon 6 */
178*4882a593Smuzhiyun "LEN0092", /* X1 Carbon 6 */
179*4882a593Smuzhiyun "LEN0093", /* T480 */
180*4882a593Smuzhiyun "LEN0096", /* X280 */
181*4882a593Smuzhiyun "LEN0097", /* X280 -> ALPS trackpoint */
182*4882a593Smuzhiyun "LEN0099", /* X1 Extreme Gen 1 / P1 Gen 1 */
183*4882a593Smuzhiyun "LEN009b", /* T580 */
184*4882a593Smuzhiyun "LEN0402", /* X1 Extreme Gen 2 / P1 Gen 2 */
185*4882a593Smuzhiyun "LEN200f", /* T450s */
186*4882a593Smuzhiyun "LEN2044", /* L470 */
187*4882a593Smuzhiyun "LEN2054", /* E480 */
188*4882a593Smuzhiyun "LEN2055", /* E580 */
189*4882a593Smuzhiyun "LEN2068", /* T14 Gen 1 */
190*4882a593Smuzhiyun "SYN3052", /* HP EliteBook 840 G4 */
191*4882a593Smuzhiyun "SYN3221", /* HP 15-ay000 */
192*4882a593Smuzhiyun "SYN323d", /* HP Spectre X360 13-w013dx */
193*4882a593Smuzhiyun "SYN3257", /* HP Envy 13-ad105ng */
194*4882a593Smuzhiyun "SYN3286", /* HP Laptop 15-da3001TU */
195*4882a593Smuzhiyun NULL
196*4882a593Smuzhiyun };
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun static const char * const forcepad_pnp_ids[] = {
199*4882a593Smuzhiyun "SYN300D",
200*4882a593Smuzhiyun "SYN3014",
201*4882a593Smuzhiyun NULL
202*4882a593Smuzhiyun };
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /*
205*4882a593Smuzhiyun * Send a command to the synaptics touchpad by special commands
206*4882a593Smuzhiyun */
synaptics_send_cmd(struct psmouse * psmouse,u8 cmd,u8 * param)207*4882a593Smuzhiyun static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun int error;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun error = ps2_sliced_command(&psmouse->ps2dev, cmd);
212*4882a593Smuzhiyun if (error)
213*4882a593Smuzhiyun return error;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO);
216*4882a593Smuzhiyun if (error)
217*4882a593Smuzhiyun return error;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun return 0;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
synaptics_query_int(struct psmouse * psmouse,u8 query_cmd,u32 * val)222*4882a593Smuzhiyun static int synaptics_query_int(struct psmouse *psmouse, u8 query_cmd, u32 *val)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun int error;
225*4882a593Smuzhiyun union {
226*4882a593Smuzhiyun __be32 be_val;
227*4882a593Smuzhiyun char buf[4];
228*4882a593Smuzhiyun } resp = { 0 };
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun error = synaptics_send_cmd(psmouse, query_cmd, resp.buf + 1);
231*4882a593Smuzhiyun if (error)
232*4882a593Smuzhiyun return error;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun *val = be32_to_cpu(resp.be_val);
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun /*
239*4882a593Smuzhiyun * Identify Touchpad
240*4882a593Smuzhiyun * See also the SYN_ID_* macros
241*4882a593Smuzhiyun */
synaptics_identify(struct psmouse * psmouse,struct synaptics_device_info * info)242*4882a593Smuzhiyun static int synaptics_identify(struct psmouse *psmouse,
243*4882a593Smuzhiyun struct synaptics_device_info *info)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun int error;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun error = synaptics_query_int(psmouse, SYN_QUE_IDENTIFY, &info->identity);
248*4882a593Smuzhiyun if (error)
249*4882a593Smuzhiyun return error;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /*
255*4882a593Smuzhiyun * Read the model-id bytes from the touchpad
256*4882a593Smuzhiyun * see also SYN_MODEL_* macros
257*4882a593Smuzhiyun */
synaptics_model_id(struct psmouse * psmouse,struct synaptics_device_info * info)258*4882a593Smuzhiyun static int synaptics_model_id(struct psmouse *psmouse,
259*4882a593Smuzhiyun struct synaptics_device_info *info)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun return synaptics_query_int(psmouse, SYN_QUE_MODEL, &info->model_id);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /*
265*4882a593Smuzhiyun * Read the firmware id from the touchpad
266*4882a593Smuzhiyun */
synaptics_firmware_id(struct psmouse * psmouse,struct synaptics_device_info * info)267*4882a593Smuzhiyun static int synaptics_firmware_id(struct psmouse *psmouse,
268*4882a593Smuzhiyun struct synaptics_device_info *info)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun return synaptics_query_int(psmouse, SYN_QUE_FIRMWARE_ID,
271*4882a593Smuzhiyun &info->firmware_id);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun /*
275*4882a593Smuzhiyun * Read the board id and the "More Extended Queries" from the touchpad
276*4882a593Smuzhiyun * The board id is encoded in the "QUERY MODES" response
277*4882a593Smuzhiyun */
synaptics_query_modes(struct psmouse * psmouse,struct synaptics_device_info * info)278*4882a593Smuzhiyun static int synaptics_query_modes(struct psmouse *psmouse,
279*4882a593Smuzhiyun struct synaptics_device_info *info)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun u8 bid[3];
282*4882a593Smuzhiyun int error;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* firmwares prior 7.5 have no board_id encoded */
285*4882a593Smuzhiyun if (SYN_ID_FULL(info->identity) < 0x705)
286*4882a593Smuzhiyun return 0;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun error = synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid);
289*4882a593Smuzhiyun if (error)
290*4882a593Smuzhiyun return error;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun info->board_id = ((bid[0] & 0xfc) << 6) | bid[1];
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (SYN_MEXT_CAP_BIT(bid[0]))
295*4882a593Smuzhiyun return synaptics_query_int(psmouse, SYN_QUE_MEXT_CAPAB_10,
296*4882a593Smuzhiyun &info->ext_cap_10);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /*
302*4882a593Smuzhiyun * Read the capability-bits from the touchpad
303*4882a593Smuzhiyun * see also the SYN_CAP_* macros
304*4882a593Smuzhiyun */
synaptics_capability(struct psmouse * psmouse,struct synaptics_device_info * info)305*4882a593Smuzhiyun static int synaptics_capability(struct psmouse *psmouse,
306*4882a593Smuzhiyun struct synaptics_device_info *info)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun int error;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun error = synaptics_query_int(psmouse, SYN_QUE_CAPABILITIES,
311*4882a593Smuzhiyun &info->capabilities);
312*4882a593Smuzhiyun if (error)
313*4882a593Smuzhiyun return error;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun info->ext_cap = info->ext_cap_0c = 0;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /*
318*4882a593Smuzhiyun * Older firmwares had submodel ID fixed to 0x47
319*4882a593Smuzhiyun */
320*4882a593Smuzhiyun if (SYN_ID_FULL(info->identity) < 0x705 &&
321*4882a593Smuzhiyun SYN_CAP_SUBMODEL_ID(info->capabilities) != 0x47) {
322*4882a593Smuzhiyun return -ENXIO;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun /*
326*4882a593Smuzhiyun * Unless capExtended is set the rest of the flags should be ignored
327*4882a593Smuzhiyun */
328*4882a593Smuzhiyun if (!SYN_CAP_EXTENDED(info->capabilities))
329*4882a593Smuzhiyun info->capabilities = 0;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 1) {
332*4882a593Smuzhiyun error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB,
333*4882a593Smuzhiyun &info->ext_cap);
334*4882a593Smuzhiyun if (error) {
335*4882a593Smuzhiyun psmouse_warn(psmouse,
336*4882a593Smuzhiyun "device claims to have extended capabilities, but I'm not able to read them.\n");
337*4882a593Smuzhiyun } else {
338*4882a593Smuzhiyun /*
339*4882a593Smuzhiyun * if nExtBtn is greater than 8 it should be considered
340*4882a593Smuzhiyun * invalid and treated as 0
341*4882a593Smuzhiyun */
342*4882a593Smuzhiyun if (SYN_CAP_MULTI_BUTTON_NO(info->ext_cap) > 8)
343*4882a593Smuzhiyun info->ext_cap &= ~SYN_CAP_MB_MASK;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 4) {
348*4882a593Smuzhiyun error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB_0C,
349*4882a593Smuzhiyun &info->ext_cap_0c);
350*4882a593Smuzhiyun if (error)
351*4882a593Smuzhiyun psmouse_warn(psmouse,
352*4882a593Smuzhiyun "device claims to have extended capability 0x0c, but I'm not able to read it.\n");
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun return 0;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun /*
359*4882a593Smuzhiyun * Read touchpad resolution and maximum reported coordinates
360*4882a593Smuzhiyun * Resolution is left zero if touchpad does not support the query
361*4882a593Smuzhiyun */
synaptics_resolution(struct psmouse * psmouse,struct synaptics_device_info * info)362*4882a593Smuzhiyun static int synaptics_resolution(struct psmouse *psmouse,
363*4882a593Smuzhiyun struct synaptics_device_info *info)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun u8 resp[3];
366*4882a593Smuzhiyun int error;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (SYN_ID_MAJOR(info->identity) < 4)
369*4882a593Smuzhiyun return 0;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun error = synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp);
372*4882a593Smuzhiyun if (!error) {
373*4882a593Smuzhiyun if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) {
374*4882a593Smuzhiyun info->x_res = resp[0]; /* x resolution in units/mm */
375*4882a593Smuzhiyun info->y_res = resp[2]; /* y resolution in units/mm */
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 5 &&
380*4882a593Smuzhiyun SYN_CAP_MAX_DIMENSIONS(info->ext_cap_0c)) {
381*4882a593Smuzhiyun error = synaptics_send_cmd(psmouse,
382*4882a593Smuzhiyun SYN_QUE_EXT_MAX_COORDS, resp);
383*4882a593Smuzhiyun if (error) {
384*4882a593Smuzhiyun psmouse_warn(psmouse,
385*4882a593Smuzhiyun "device claims to have max coordinates query, but I'm not able to read it.\n");
386*4882a593Smuzhiyun } else {
387*4882a593Smuzhiyun info->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
388*4882a593Smuzhiyun info->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
389*4882a593Smuzhiyun psmouse_info(psmouse,
390*4882a593Smuzhiyun "queried max coordinates: x [..%d], y [..%d]\n",
391*4882a593Smuzhiyun info->x_max, info->y_max);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun if (SYN_CAP_MIN_DIMENSIONS(info->ext_cap_0c) &&
396*4882a593Smuzhiyun (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 7 ||
397*4882a593Smuzhiyun /*
398*4882a593Smuzhiyun * Firmware v8.1 does not report proper number of extended
399*4882a593Smuzhiyun * capabilities, but has been proven to report correct min
400*4882a593Smuzhiyun * coordinates.
401*4882a593Smuzhiyun */
402*4882a593Smuzhiyun SYN_ID_FULL(info->identity) == 0x801)) {
403*4882a593Smuzhiyun error = synaptics_send_cmd(psmouse,
404*4882a593Smuzhiyun SYN_QUE_EXT_MIN_COORDS, resp);
405*4882a593Smuzhiyun if (error) {
406*4882a593Smuzhiyun psmouse_warn(psmouse,
407*4882a593Smuzhiyun "device claims to have min coordinates query, but I'm not able to read it.\n");
408*4882a593Smuzhiyun } else {
409*4882a593Smuzhiyun info->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
410*4882a593Smuzhiyun info->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
411*4882a593Smuzhiyun psmouse_info(psmouse,
412*4882a593Smuzhiyun "queried min coordinates: x [%d..], y [%d..]\n",
413*4882a593Smuzhiyun info->x_min, info->y_min);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
synaptics_query_hardware(struct psmouse * psmouse,struct synaptics_device_info * info)420*4882a593Smuzhiyun static int synaptics_query_hardware(struct psmouse *psmouse,
421*4882a593Smuzhiyun struct synaptics_device_info *info)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun int error;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun memset(info, 0, sizeof(*info));
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun error = synaptics_identify(psmouse, info);
428*4882a593Smuzhiyun if (error)
429*4882a593Smuzhiyun return error;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun error = synaptics_model_id(psmouse, info);
432*4882a593Smuzhiyun if (error)
433*4882a593Smuzhiyun return error;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun error = synaptics_firmware_id(psmouse, info);
436*4882a593Smuzhiyun if (error)
437*4882a593Smuzhiyun return error;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun error = synaptics_query_modes(psmouse, info);
440*4882a593Smuzhiyun if (error)
441*4882a593Smuzhiyun return error;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun error = synaptics_capability(psmouse, info);
444*4882a593Smuzhiyun if (error)
445*4882a593Smuzhiyun return error;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun error = synaptics_resolution(psmouse, info);
448*4882a593Smuzhiyun if (error)
449*4882a593Smuzhiyun return error;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun return 0;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun #endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun #ifdef CONFIG_MOUSE_PS2_SYNAPTICS
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun static bool cr48_profile_sensor;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun #define ANY_BOARD_ID 0
461*4882a593Smuzhiyun struct min_max_quirk {
462*4882a593Smuzhiyun const char * const *pnp_ids;
463*4882a593Smuzhiyun struct {
464*4882a593Smuzhiyun u32 min, max;
465*4882a593Smuzhiyun } board_id;
466*4882a593Smuzhiyun u32 x_min, x_max, y_min, y_max;
467*4882a593Smuzhiyun };
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun static const struct min_max_quirk min_max_pnpid_table[] = {
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun (const char * const []){"LEN0033", NULL},
472*4882a593Smuzhiyun {ANY_BOARD_ID, ANY_BOARD_ID},
473*4882a593Smuzhiyun 1024, 5052, 2258, 4832
474*4882a593Smuzhiyun },
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun (const char * const []){"LEN0042", NULL},
477*4882a593Smuzhiyun {ANY_BOARD_ID, ANY_BOARD_ID},
478*4882a593Smuzhiyun 1232, 5710, 1156, 4696
479*4882a593Smuzhiyun },
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun (const char * const []){"LEN0034", "LEN0036", "LEN0037",
482*4882a593Smuzhiyun "LEN0039", "LEN2002", "LEN2004",
483*4882a593Smuzhiyun NULL},
484*4882a593Smuzhiyun {ANY_BOARD_ID, 2961},
485*4882a593Smuzhiyun 1024, 5112, 2024, 4832
486*4882a593Smuzhiyun },
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun (const char * const []){"LEN2000", NULL},
489*4882a593Smuzhiyun {ANY_BOARD_ID, ANY_BOARD_ID},
490*4882a593Smuzhiyun 1024, 5113, 2021, 4832
491*4882a593Smuzhiyun },
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun (const char * const []){"LEN2001", NULL},
494*4882a593Smuzhiyun {ANY_BOARD_ID, ANY_BOARD_ID},
495*4882a593Smuzhiyun 1024, 5022, 2508, 4832
496*4882a593Smuzhiyun },
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun (const char * const []){"LEN2006", NULL},
499*4882a593Smuzhiyun {2691, 2691},
500*4882a593Smuzhiyun 1024, 5045, 2457, 4832
501*4882a593Smuzhiyun },
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun (const char * const []){"LEN2006", NULL},
504*4882a593Smuzhiyun {ANY_BOARD_ID, ANY_BOARD_ID},
505*4882a593Smuzhiyun 1264, 5675, 1171, 4688
506*4882a593Smuzhiyun },
507*4882a593Smuzhiyun { }
508*4882a593Smuzhiyun };
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /*****************************************************************************
511*4882a593Smuzhiyun * Synaptics communications functions
512*4882a593Smuzhiyun ****************************************************************************/
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun /*
515*4882a593Smuzhiyun * Synaptics touchpads report the y coordinate from bottom to top, which is
516*4882a593Smuzhiyun * opposite from what userspace expects.
517*4882a593Smuzhiyun * This function is used to invert y before reporting.
518*4882a593Smuzhiyun */
synaptics_invert_y(int y)519*4882a593Smuzhiyun static int synaptics_invert_y(int y)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun return YMAX_NOMINAL + YMIN_NOMINAL - y;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /*
525*4882a593Smuzhiyun * Apply quirk(s) if the hardware matches
526*4882a593Smuzhiyun */
synaptics_apply_quirks(struct psmouse * psmouse,struct synaptics_device_info * info)527*4882a593Smuzhiyun static void synaptics_apply_quirks(struct psmouse *psmouse,
528*4882a593Smuzhiyun struct synaptics_device_info *info)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun int i;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) {
533*4882a593Smuzhiyun if (!psmouse_matches_pnp_id(psmouse,
534*4882a593Smuzhiyun min_max_pnpid_table[i].pnp_ids))
535*4882a593Smuzhiyun continue;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID &&
538*4882a593Smuzhiyun info->board_id < min_max_pnpid_table[i].board_id.min)
539*4882a593Smuzhiyun continue;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID &&
542*4882a593Smuzhiyun info->board_id > min_max_pnpid_table[i].board_id.max)
543*4882a593Smuzhiyun continue;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun info->x_min = min_max_pnpid_table[i].x_min;
546*4882a593Smuzhiyun info->x_max = min_max_pnpid_table[i].x_max;
547*4882a593Smuzhiyun info->y_min = min_max_pnpid_table[i].y_min;
548*4882a593Smuzhiyun info->y_max = min_max_pnpid_table[i].y_max;
549*4882a593Smuzhiyun psmouse_info(psmouse,
550*4882a593Smuzhiyun "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n",
551*4882a593Smuzhiyun info->x_min, info->x_max,
552*4882a593Smuzhiyun info->y_min, info->y_max);
553*4882a593Smuzhiyun break;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun
synaptics_has_agm(struct synaptics_data * priv)557*4882a593Smuzhiyun static bool synaptics_has_agm(struct synaptics_data *priv)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun return (SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) ||
560*4882a593Smuzhiyun SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c));
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
synaptics_set_advanced_gesture_mode(struct psmouse * psmouse)563*4882a593Smuzhiyun static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun static u8 param = 0xc8;
566*4882a593Smuzhiyun int error;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun error = ps2_sliced_command(&psmouse->ps2dev, SYN_QUE_MODEL);
569*4882a593Smuzhiyun if (error)
570*4882a593Smuzhiyun return error;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun error = ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE);
573*4882a593Smuzhiyun if (error)
574*4882a593Smuzhiyun return error;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun return 0;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
synaptics_set_mode(struct psmouse * psmouse)579*4882a593Smuzhiyun static int synaptics_set_mode(struct psmouse *psmouse)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
582*4882a593Smuzhiyun int error;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun priv->mode = 0;
585*4882a593Smuzhiyun if (priv->absolute_mode)
586*4882a593Smuzhiyun priv->mode |= SYN_BIT_ABSOLUTE_MODE;
587*4882a593Smuzhiyun if (priv->disable_gesture)
588*4882a593Smuzhiyun priv->mode |= SYN_BIT_DISABLE_GESTURE;
589*4882a593Smuzhiyun if (psmouse->rate >= 80)
590*4882a593Smuzhiyun priv->mode |= SYN_BIT_HIGH_RATE;
591*4882a593Smuzhiyun if (SYN_CAP_EXTENDED(priv->info.capabilities))
592*4882a593Smuzhiyun priv->mode |= SYN_BIT_W_MODE;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun error = synaptics_mode_cmd(psmouse, priv->mode);
595*4882a593Smuzhiyun if (error)
596*4882a593Smuzhiyun return error;
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun if (priv->absolute_mode && synaptics_has_agm(priv)) {
599*4882a593Smuzhiyun error = synaptics_set_advanced_gesture_mode(psmouse);
600*4882a593Smuzhiyun if (error) {
601*4882a593Smuzhiyun psmouse_err(psmouse,
602*4882a593Smuzhiyun "Advanced gesture mode init failed: %d\n",
603*4882a593Smuzhiyun error);
604*4882a593Smuzhiyun return error;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun return 0;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
synaptics_set_rate(struct psmouse * psmouse,unsigned int rate)611*4882a593Smuzhiyun static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun if (rate >= 80) {
616*4882a593Smuzhiyun priv->mode |= SYN_BIT_HIGH_RATE;
617*4882a593Smuzhiyun psmouse->rate = 80;
618*4882a593Smuzhiyun } else {
619*4882a593Smuzhiyun priv->mode &= ~SYN_BIT_HIGH_RATE;
620*4882a593Smuzhiyun psmouse->rate = 40;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun synaptics_mode_cmd(psmouse, priv->mode);
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun /*****************************************************************************
627*4882a593Smuzhiyun * Synaptics pass-through PS/2 port support
628*4882a593Smuzhiyun ****************************************************************************/
synaptics_pt_write(struct serio * serio,u8 c)629*4882a593Smuzhiyun static int synaptics_pt_write(struct serio *serio, u8 c)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun struct psmouse *parent = serio_get_drvdata(serio->parent);
632*4882a593Smuzhiyun u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
633*4882a593Smuzhiyun int error;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun error = ps2_sliced_command(&parent->ps2dev, c);
636*4882a593Smuzhiyun if (error)
637*4882a593Smuzhiyun return error;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun error = ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE);
640*4882a593Smuzhiyun if (error)
641*4882a593Smuzhiyun return error;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun return 0;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
synaptics_pt_start(struct serio * serio)646*4882a593Smuzhiyun static int synaptics_pt_start(struct serio *serio)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun struct psmouse *parent = serio_get_drvdata(serio->parent);
649*4882a593Smuzhiyun struct synaptics_data *priv = parent->private;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun serio_pause_rx(parent->ps2dev.serio);
652*4882a593Smuzhiyun priv->pt_port = serio;
653*4882a593Smuzhiyun serio_continue_rx(parent->ps2dev.serio);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun return 0;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun
synaptics_pt_stop(struct serio * serio)658*4882a593Smuzhiyun static void synaptics_pt_stop(struct serio *serio)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun struct psmouse *parent = serio_get_drvdata(serio->parent);
661*4882a593Smuzhiyun struct synaptics_data *priv = parent->private;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun serio_pause_rx(parent->ps2dev.serio);
664*4882a593Smuzhiyun priv->pt_port = NULL;
665*4882a593Smuzhiyun serio_continue_rx(parent->ps2dev.serio);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
synaptics_is_pt_packet(u8 * buf)668*4882a593Smuzhiyun static int synaptics_is_pt_packet(u8 *buf)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun
synaptics_pass_pt_packet(struct serio * ptport,u8 * packet)673*4882a593Smuzhiyun static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun struct psmouse *child = serio_get_drvdata(ptport);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun if (child && child->state == PSMOUSE_ACTIVATED) {
678*4882a593Smuzhiyun serio_interrupt(ptport, packet[1], 0);
679*4882a593Smuzhiyun serio_interrupt(ptport, packet[4], 0);
680*4882a593Smuzhiyun serio_interrupt(ptport, packet[5], 0);
681*4882a593Smuzhiyun if (child->pktsize == 4)
682*4882a593Smuzhiyun serio_interrupt(ptport, packet[2], 0);
683*4882a593Smuzhiyun } else {
684*4882a593Smuzhiyun serio_interrupt(ptport, packet[1], 0);
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
synaptics_pt_activate(struct psmouse * psmouse)688*4882a593Smuzhiyun static void synaptics_pt_activate(struct psmouse *psmouse)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
691*4882a593Smuzhiyun struct psmouse *child = serio_get_drvdata(priv->pt_port);
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun /* adjust the touchpad to child's choice of protocol */
694*4882a593Smuzhiyun if (child) {
695*4882a593Smuzhiyun if (child->pktsize == 4)
696*4882a593Smuzhiyun priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
697*4882a593Smuzhiyun else
698*4882a593Smuzhiyun priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun if (synaptics_mode_cmd(psmouse, priv->mode))
701*4882a593Smuzhiyun psmouse_warn(psmouse,
702*4882a593Smuzhiyun "failed to switch guest protocol\n");
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
synaptics_pt_create(struct psmouse * psmouse)706*4882a593Smuzhiyun static void synaptics_pt_create(struct psmouse *psmouse)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun struct serio *serio;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
711*4882a593Smuzhiyun if (!serio) {
712*4882a593Smuzhiyun psmouse_err(psmouse,
713*4882a593Smuzhiyun "not enough memory for pass-through port\n");
714*4882a593Smuzhiyun return;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun serio->id.type = SERIO_PS_PSTHRU;
718*4882a593Smuzhiyun strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
719*4882a593Smuzhiyun strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->phys));
720*4882a593Smuzhiyun serio->write = synaptics_pt_write;
721*4882a593Smuzhiyun serio->start = synaptics_pt_start;
722*4882a593Smuzhiyun serio->stop = synaptics_pt_stop;
723*4882a593Smuzhiyun serio->parent = psmouse->ps2dev.serio;
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun psmouse->pt_activate = synaptics_pt_activate;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun psmouse_info(psmouse, "serio: %s port at %s\n",
728*4882a593Smuzhiyun serio->name, psmouse->phys);
729*4882a593Smuzhiyun serio_register_port(serio);
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /*****************************************************************************
733*4882a593Smuzhiyun * Functions to interpret the absolute mode packets
734*4882a593Smuzhiyun ****************************************************************************/
735*4882a593Smuzhiyun
synaptics_parse_agm(const u8 buf[],struct synaptics_data * priv,struct synaptics_hw_state * hw)736*4882a593Smuzhiyun static void synaptics_parse_agm(const u8 buf[],
737*4882a593Smuzhiyun struct synaptics_data *priv,
738*4882a593Smuzhiyun struct synaptics_hw_state *hw)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun struct synaptics_hw_state *agm = &priv->agm;
741*4882a593Smuzhiyun int agm_packet_type;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun agm_packet_type = (buf[5] & 0x30) >> 4;
744*4882a593Smuzhiyun switch (agm_packet_type) {
745*4882a593Smuzhiyun case 1:
746*4882a593Smuzhiyun /* Gesture packet: (x, y, z) half resolution */
747*4882a593Smuzhiyun agm->w = hw->w;
748*4882a593Smuzhiyun agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
749*4882a593Smuzhiyun agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
750*4882a593Smuzhiyun agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
751*4882a593Smuzhiyun break;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun case 2:
754*4882a593Smuzhiyun /* AGM-CONTACT packet: we are only interested in the count */
755*4882a593Smuzhiyun priv->agm_count = buf[1];
756*4882a593Smuzhiyun break;
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun default:
759*4882a593Smuzhiyun break;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun
synaptics_parse_ext_buttons(const u8 buf[],struct synaptics_data * priv,struct synaptics_hw_state * hw)763*4882a593Smuzhiyun static void synaptics_parse_ext_buttons(const u8 buf[],
764*4882a593Smuzhiyun struct synaptics_data *priv,
765*4882a593Smuzhiyun struct synaptics_hw_state *hw)
766*4882a593Smuzhiyun {
767*4882a593Smuzhiyun unsigned int ext_bits =
768*4882a593Smuzhiyun (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1;
769*4882a593Smuzhiyun unsigned int ext_mask = GENMASK(ext_bits - 1, 0);
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun hw->ext_buttons = buf[4] & ext_mask;
772*4882a593Smuzhiyun hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
synaptics_parse_hw_state(const u8 buf[],struct synaptics_data * priv,struct synaptics_hw_state * hw)775*4882a593Smuzhiyun static int synaptics_parse_hw_state(const u8 buf[],
776*4882a593Smuzhiyun struct synaptics_data *priv,
777*4882a593Smuzhiyun struct synaptics_hw_state *hw)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun memset(hw, 0, sizeof(struct synaptics_hw_state));
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun if (SYN_MODEL_NEWABS(priv->info.model_id)) {
782*4882a593Smuzhiyun hw->w = (((buf[0] & 0x30) >> 2) |
783*4882a593Smuzhiyun ((buf[0] & 0x04) >> 1) |
784*4882a593Smuzhiyun ((buf[3] & 0x04) >> 2));
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun if (synaptics_has_agm(priv) && hw->w == 2) {
787*4882a593Smuzhiyun synaptics_parse_agm(buf, priv, hw);
788*4882a593Smuzhiyun return 1;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun hw->x = (((buf[3] & 0x10) << 8) |
792*4882a593Smuzhiyun ((buf[1] & 0x0f) << 8) |
793*4882a593Smuzhiyun buf[4]);
794*4882a593Smuzhiyun hw->y = (((buf[3] & 0x20) << 7) |
795*4882a593Smuzhiyun ((buf[1] & 0xf0) << 4) |
796*4882a593Smuzhiyun buf[5]);
797*4882a593Smuzhiyun hw->z = buf[2];
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun hw->left = (buf[0] & 0x01) ? 1 : 0;
800*4882a593Smuzhiyun hw->right = (buf[0] & 0x02) ? 1 : 0;
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun if (priv->is_forcepad) {
803*4882a593Smuzhiyun /*
804*4882a593Smuzhiyun * ForcePads, like Clickpads, use middle button
805*4882a593Smuzhiyun * bits to report primary button clicks.
806*4882a593Smuzhiyun * Unfortunately they report primary button not
807*4882a593Smuzhiyun * only when user presses on the pad above certain
808*4882a593Smuzhiyun * threshold, but also when there are more than one
809*4882a593Smuzhiyun * finger on the touchpad, which interferes with
810*4882a593Smuzhiyun * out multi-finger gestures.
811*4882a593Smuzhiyun */
812*4882a593Smuzhiyun if (hw->z == 0) {
813*4882a593Smuzhiyun /* No contacts */
814*4882a593Smuzhiyun priv->press = priv->report_press = false;
815*4882a593Smuzhiyun } else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) {
816*4882a593Smuzhiyun /*
817*4882a593Smuzhiyun * Single-finger touch with pressure above
818*4882a593Smuzhiyun * the threshold. If pressure stays long
819*4882a593Smuzhiyun * enough, we'll start reporting primary
820*4882a593Smuzhiyun * button. We rely on the device continuing
821*4882a593Smuzhiyun * sending data even if finger does not
822*4882a593Smuzhiyun * move.
823*4882a593Smuzhiyun */
824*4882a593Smuzhiyun if (!priv->press) {
825*4882a593Smuzhiyun priv->press_start = jiffies;
826*4882a593Smuzhiyun priv->press = true;
827*4882a593Smuzhiyun } else if (time_after(jiffies,
828*4882a593Smuzhiyun priv->press_start +
829*4882a593Smuzhiyun msecs_to_jiffies(50))) {
830*4882a593Smuzhiyun priv->report_press = true;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun } else {
833*4882a593Smuzhiyun priv->press = false;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun hw->left = priv->report_press;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun } else if (SYN_CAP_CLICKPAD(priv->info.ext_cap_0c)) {
839*4882a593Smuzhiyun /*
840*4882a593Smuzhiyun * Clickpad's button is transmitted as middle button,
841*4882a593Smuzhiyun * however, since it is primary button, we will report
842*4882a593Smuzhiyun * it as BTN_LEFT.
843*4882a593Smuzhiyun */
844*4882a593Smuzhiyun hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun } else if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) {
847*4882a593Smuzhiyun hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
848*4882a593Smuzhiyun if (hw->w == 2)
849*4882a593Smuzhiyun hw->scroll = (s8)buf[1];
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) {
853*4882a593Smuzhiyun hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
854*4882a593Smuzhiyun hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun if (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) > 0 &&
858*4882a593Smuzhiyun ((buf[0] ^ buf[3]) & 0x02)) {
859*4882a593Smuzhiyun synaptics_parse_ext_buttons(buf, priv, hw);
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun } else {
862*4882a593Smuzhiyun hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
863*4882a593Smuzhiyun hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
866*4882a593Smuzhiyun hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun hw->left = (buf[0] & 0x01) ? 1 : 0;
869*4882a593Smuzhiyun hw->right = (buf[0] & 0x02) ? 1 : 0;
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun /*
873*4882a593Smuzhiyun * Convert wrap-around values to negative. (X|Y)_MAX_POSITIVE
874*4882a593Smuzhiyun * is used by some firmware to indicate a finger at the edge of
875*4882a593Smuzhiyun * the touchpad whose precise position cannot be determined, so
876*4882a593Smuzhiyun * convert these values to the maximum axis value.
877*4882a593Smuzhiyun */
878*4882a593Smuzhiyun if (hw->x > X_MAX_POSITIVE)
879*4882a593Smuzhiyun hw->x -= 1 << ABS_POS_BITS;
880*4882a593Smuzhiyun else if (hw->x == X_MAX_POSITIVE)
881*4882a593Smuzhiyun hw->x = XMAX;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun if (hw->y > Y_MAX_POSITIVE)
884*4882a593Smuzhiyun hw->y -= 1 << ABS_POS_BITS;
885*4882a593Smuzhiyun else if (hw->y == Y_MAX_POSITIVE)
886*4882a593Smuzhiyun hw->y = YMAX;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun return 0;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
synaptics_report_semi_mt_slot(struct input_dev * dev,int slot,bool active,int x,int y)891*4882a593Smuzhiyun static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot,
892*4882a593Smuzhiyun bool active, int x, int y)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun input_mt_slot(dev, slot);
895*4882a593Smuzhiyun input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
896*4882a593Smuzhiyun if (active) {
897*4882a593Smuzhiyun input_report_abs(dev, ABS_MT_POSITION_X, x);
898*4882a593Smuzhiyun input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(y));
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
synaptics_report_semi_mt_data(struct input_dev * dev,const struct synaptics_hw_state * a,const struct synaptics_hw_state * b,int num_fingers)902*4882a593Smuzhiyun static void synaptics_report_semi_mt_data(struct input_dev *dev,
903*4882a593Smuzhiyun const struct synaptics_hw_state *a,
904*4882a593Smuzhiyun const struct synaptics_hw_state *b,
905*4882a593Smuzhiyun int num_fingers)
906*4882a593Smuzhiyun {
907*4882a593Smuzhiyun if (num_fingers >= 2) {
908*4882a593Smuzhiyun synaptics_report_semi_mt_slot(dev, 0, true, min(a->x, b->x),
909*4882a593Smuzhiyun min(a->y, b->y));
910*4882a593Smuzhiyun synaptics_report_semi_mt_slot(dev, 1, true, max(a->x, b->x),
911*4882a593Smuzhiyun max(a->y, b->y));
912*4882a593Smuzhiyun } else if (num_fingers == 1) {
913*4882a593Smuzhiyun synaptics_report_semi_mt_slot(dev, 0, true, a->x, a->y);
914*4882a593Smuzhiyun synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
915*4882a593Smuzhiyun } else {
916*4882a593Smuzhiyun synaptics_report_semi_mt_slot(dev, 0, false, 0, 0);
917*4882a593Smuzhiyun synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun
synaptics_report_ext_buttons(struct psmouse * psmouse,const struct synaptics_hw_state * hw)921*4882a593Smuzhiyun static void synaptics_report_ext_buttons(struct psmouse *psmouse,
922*4882a593Smuzhiyun const struct synaptics_hw_state *hw)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
925*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
926*4882a593Smuzhiyun int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1;
927*4882a593Smuzhiyun int i;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun if (!SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap))
930*4882a593Smuzhiyun return;
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun /* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */
933*4882a593Smuzhiyun if ((SYN_ID_FULL(priv->info.identity) == 0x801 ||
934*4882a593Smuzhiyun SYN_ID_FULL(priv->info.identity) == 0x802) &&
935*4882a593Smuzhiyun !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02))
936*4882a593Smuzhiyun return;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun if (!SYN_CAP_EXT_BUTTONS_STICK(priv->info.ext_cap_10)) {
939*4882a593Smuzhiyun for (i = 0; i < ext_bits; i++) {
940*4882a593Smuzhiyun input_report_key(dev, BTN_0 + 2 * i,
941*4882a593Smuzhiyun hw->ext_buttons & BIT(i));
942*4882a593Smuzhiyun input_report_key(dev, BTN_1 + 2 * i,
943*4882a593Smuzhiyun hw->ext_buttons & BIT(i + ext_bits));
944*4882a593Smuzhiyun }
945*4882a593Smuzhiyun return;
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun /*
949*4882a593Smuzhiyun * This generation of touchpads has the trackstick buttons
950*4882a593Smuzhiyun * physically wired to the touchpad. Re-route them through
951*4882a593Smuzhiyun * the pass-through interface.
952*4882a593Smuzhiyun */
953*4882a593Smuzhiyun if (priv->pt_port) {
954*4882a593Smuzhiyun u8 pt_buttons;
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun /* The trackstick expects at most 3 buttons */
957*4882a593Smuzhiyun pt_buttons = SYN_EXT_BUTTON_STICK_L(hw->ext_buttons) |
958*4882a593Smuzhiyun SYN_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
959*4882a593Smuzhiyun SYN_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun serio_interrupt(priv->pt_port,
962*4882a593Smuzhiyun PSMOUSE_OOB_EXTRA_BTNS, SERIO_OOB_DATA);
963*4882a593Smuzhiyun serio_interrupt(priv->pt_port, pt_buttons, SERIO_OOB_DATA);
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun
synaptics_report_buttons(struct psmouse * psmouse,const struct synaptics_hw_state * hw)967*4882a593Smuzhiyun static void synaptics_report_buttons(struct psmouse *psmouse,
968*4882a593Smuzhiyun const struct synaptics_hw_state *hw)
969*4882a593Smuzhiyun {
970*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
971*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun input_report_key(dev, BTN_LEFT, hw->left);
974*4882a593Smuzhiyun input_report_key(dev, BTN_RIGHT, hw->right);
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities))
977*4882a593Smuzhiyun input_report_key(dev, BTN_MIDDLE, hw->middle);
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) {
980*4882a593Smuzhiyun input_report_key(dev, BTN_FORWARD, hw->up);
981*4882a593Smuzhiyun input_report_key(dev, BTN_BACK, hw->down);
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun synaptics_report_ext_buttons(psmouse, hw);
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun
synaptics_report_mt_data(struct psmouse * psmouse,const struct synaptics_hw_state * sgm,int num_fingers)987*4882a593Smuzhiyun static void synaptics_report_mt_data(struct psmouse *psmouse,
988*4882a593Smuzhiyun const struct synaptics_hw_state *sgm,
989*4882a593Smuzhiyun int num_fingers)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
992*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
993*4882a593Smuzhiyun const struct synaptics_hw_state *hw[2] = { sgm, &priv->agm };
994*4882a593Smuzhiyun struct input_mt_pos pos[2];
995*4882a593Smuzhiyun int slot[2], nsemi, i;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun nsemi = clamp_val(num_fingers, 0, 2);
998*4882a593Smuzhiyun
999*4882a593Smuzhiyun for (i = 0; i < nsemi; i++) {
1000*4882a593Smuzhiyun pos[i].x = hw[i]->x;
1001*4882a593Smuzhiyun pos[i].y = synaptics_invert_y(hw[i]->y);
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->info.x_res);
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun for (i = 0; i < nsemi; i++) {
1007*4882a593Smuzhiyun input_mt_slot(dev, slot[i]);
1008*4882a593Smuzhiyun input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
1009*4882a593Smuzhiyun input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x);
1010*4882a593Smuzhiyun input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y);
1011*4882a593Smuzhiyun input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z);
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun input_mt_drop_unused(dev);
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun /* Don't use active slot count to generate BTN_TOOL events. */
1017*4882a593Smuzhiyun input_mt_report_pointer_emulation(dev, false);
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun /* Send the number of fingers reported by touchpad itself. */
1020*4882a593Smuzhiyun input_mt_report_finger_count(dev, num_fingers);
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun synaptics_report_buttons(psmouse, sgm);
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun input_sync(dev);
1025*4882a593Smuzhiyun }
1026*4882a593Smuzhiyun
synaptics_image_sensor_process(struct psmouse * psmouse,struct synaptics_hw_state * sgm)1027*4882a593Smuzhiyun static void synaptics_image_sensor_process(struct psmouse *psmouse,
1028*4882a593Smuzhiyun struct synaptics_hw_state *sgm)
1029*4882a593Smuzhiyun {
1030*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
1031*4882a593Smuzhiyun int num_fingers;
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun /*
1034*4882a593Smuzhiyun * Update mt_state using the new finger count and current mt_state.
1035*4882a593Smuzhiyun */
1036*4882a593Smuzhiyun if (sgm->z == 0)
1037*4882a593Smuzhiyun num_fingers = 0;
1038*4882a593Smuzhiyun else if (sgm->w >= 4)
1039*4882a593Smuzhiyun num_fingers = 1;
1040*4882a593Smuzhiyun else if (sgm->w == 0)
1041*4882a593Smuzhiyun num_fingers = 2;
1042*4882a593Smuzhiyun else if (sgm->w == 1)
1043*4882a593Smuzhiyun num_fingers = priv->agm_count ? priv->agm_count : 3;
1044*4882a593Smuzhiyun else
1045*4882a593Smuzhiyun num_fingers = 4;
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun /* Send resulting input events to user space */
1048*4882a593Smuzhiyun synaptics_report_mt_data(psmouse, sgm, num_fingers);
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun
synaptics_has_multifinger(struct synaptics_data * priv)1051*4882a593Smuzhiyun static bool synaptics_has_multifinger(struct synaptics_data *priv)
1052*4882a593Smuzhiyun {
1053*4882a593Smuzhiyun if (SYN_CAP_MULTIFINGER(priv->info.capabilities))
1054*4882a593Smuzhiyun return true;
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun /* Advanced gesture mode also sends multi finger data */
1057*4882a593Smuzhiyun return synaptics_has_agm(priv);
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun /*
1061*4882a593Smuzhiyun * called for each full received packet from the touchpad
1062*4882a593Smuzhiyun */
synaptics_process_packet(struct psmouse * psmouse)1063*4882a593Smuzhiyun static void synaptics_process_packet(struct psmouse *psmouse)
1064*4882a593Smuzhiyun {
1065*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
1066*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
1067*4882a593Smuzhiyun struct synaptics_device_info *info = &priv->info;
1068*4882a593Smuzhiyun struct synaptics_hw_state hw;
1069*4882a593Smuzhiyun int num_fingers;
1070*4882a593Smuzhiyun int finger_width;
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
1073*4882a593Smuzhiyun return;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) {
1076*4882a593Smuzhiyun synaptics_image_sensor_process(psmouse, &hw);
1077*4882a593Smuzhiyun return;
1078*4882a593Smuzhiyun }
1079*4882a593Smuzhiyun
1080*4882a593Smuzhiyun if (hw.scroll) {
1081*4882a593Smuzhiyun priv->scroll += hw.scroll;
1082*4882a593Smuzhiyun
1083*4882a593Smuzhiyun while (priv->scroll >= 4) {
1084*4882a593Smuzhiyun input_report_key(dev, BTN_BACK, !hw.down);
1085*4882a593Smuzhiyun input_sync(dev);
1086*4882a593Smuzhiyun input_report_key(dev, BTN_BACK, hw.down);
1087*4882a593Smuzhiyun input_sync(dev);
1088*4882a593Smuzhiyun priv->scroll -= 4;
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun while (priv->scroll <= -4) {
1091*4882a593Smuzhiyun input_report_key(dev, BTN_FORWARD, !hw.up);
1092*4882a593Smuzhiyun input_sync(dev);
1093*4882a593Smuzhiyun input_report_key(dev, BTN_FORWARD, hw.up);
1094*4882a593Smuzhiyun input_sync(dev);
1095*4882a593Smuzhiyun priv->scroll += 4;
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun return;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun if (hw.z > 0 && hw.x > 1) {
1101*4882a593Smuzhiyun num_fingers = 1;
1102*4882a593Smuzhiyun finger_width = 5;
1103*4882a593Smuzhiyun if (SYN_CAP_EXTENDED(info->capabilities)) {
1104*4882a593Smuzhiyun switch (hw.w) {
1105*4882a593Smuzhiyun case 0 ... 1:
1106*4882a593Smuzhiyun if (synaptics_has_multifinger(priv))
1107*4882a593Smuzhiyun num_fingers = hw.w + 2;
1108*4882a593Smuzhiyun break;
1109*4882a593Smuzhiyun case 2:
1110*4882a593Smuzhiyun if (SYN_MODEL_PEN(info->model_id))
1111*4882a593Smuzhiyun ; /* Nothing, treat a pen as a single finger */
1112*4882a593Smuzhiyun break;
1113*4882a593Smuzhiyun case 4 ... 15:
1114*4882a593Smuzhiyun if (SYN_CAP_PALMDETECT(info->capabilities))
1115*4882a593Smuzhiyun finger_width = hw.w;
1116*4882a593Smuzhiyun break;
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun } else {
1120*4882a593Smuzhiyun num_fingers = 0;
1121*4882a593Smuzhiyun finger_width = 0;
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun if (cr48_profile_sensor) {
1125*4882a593Smuzhiyun synaptics_report_mt_data(psmouse, &hw, num_fingers);
1126*4882a593Smuzhiyun return;
1127*4882a593Smuzhiyun }
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c))
1130*4882a593Smuzhiyun synaptics_report_semi_mt_data(dev, &hw, &priv->agm,
1131*4882a593Smuzhiyun num_fingers);
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun /* Post events
1134*4882a593Smuzhiyun * BTN_TOUCH has to be first as mousedev relies on it when doing
1135*4882a593Smuzhiyun * absolute -> relative conversion
1136*4882a593Smuzhiyun */
1137*4882a593Smuzhiyun if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
1138*4882a593Smuzhiyun if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun if (num_fingers > 0) {
1141*4882a593Smuzhiyun input_report_abs(dev, ABS_X, hw.x);
1142*4882a593Smuzhiyun input_report_abs(dev, ABS_Y, synaptics_invert_y(hw.y));
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun input_report_abs(dev, ABS_PRESSURE, hw.z);
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun if (SYN_CAP_PALMDETECT(info->capabilities))
1147*4882a593Smuzhiyun input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
1150*4882a593Smuzhiyun if (synaptics_has_multifinger(priv)) {
1151*4882a593Smuzhiyun input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
1152*4882a593Smuzhiyun input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
1153*4882a593Smuzhiyun }
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun synaptics_report_buttons(psmouse, &hw);
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun input_sync(dev);
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun
synaptics_validate_byte(struct psmouse * psmouse,int idx,enum synaptics_pkt_type pkt_type)1160*4882a593Smuzhiyun static bool synaptics_validate_byte(struct psmouse *psmouse,
1161*4882a593Smuzhiyun int idx, enum synaptics_pkt_type pkt_type)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun static const u8 newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
1164*4882a593Smuzhiyun static const u8 newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
1165*4882a593Smuzhiyun static const u8 newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
1166*4882a593Smuzhiyun static const u8 oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
1167*4882a593Smuzhiyun static const u8 oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
1168*4882a593Smuzhiyun const u8 *packet = psmouse->packet;
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun if (idx < 0 || idx > 4)
1171*4882a593Smuzhiyun return false;
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun switch (pkt_type) {
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun case SYN_NEWABS:
1176*4882a593Smuzhiyun case SYN_NEWABS_RELAXED:
1177*4882a593Smuzhiyun return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun case SYN_NEWABS_STRICT:
1180*4882a593Smuzhiyun return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun case SYN_OLDABS:
1183*4882a593Smuzhiyun return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun default:
1186*4882a593Smuzhiyun psmouse_err(psmouse, "unknown packet type %d\n", pkt_type);
1187*4882a593Smuzhiyun return false;
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun static enum synaptics_pkt_type
synaptics_detect_pkt_type(struct psmouse * psmouse)1192*4882a593Smuzhiyun synaptics_detect_pkt_type(struct psmouse *psmouse)
1193*4882a593Smuzhiyun {
1194*4882a593Smuzhiyun int i;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun for (i = 0; i < 5; i++) {
1197*4882a593Smuzhiyun if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) {
1198*4882a593Smuzhiyun psmouse_info(psmouse, "using relaxed packet validation\n");
1199*4882a593Smuzhiyun return SYN_NEWABS_RELAXED;
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun }
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun return SYN_NEWABS_STRICT;
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun
synaptics_process_byte(struct psmouse * psmouse)1206*4882a593Smuzhiyun static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
1207*4882a593Smuzhiyun {
1208*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun if (psmouse->pktcnt >= 6) { /* Full packet received */
1211*4882a593Smuzhiyun if (unlikely(priv->pkt_type == SYN_NEWABS))
1212*4882a593Smuzhiyun priv->pkt_type = synaptics_detect_pkt_type(psmouse);
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun if (SYN_CAP_PASS_THROUGH(priv->info.capabilities) &&
1215*4882a593Smuzhiyun synaptics_is_pt_packet(psmouse->packet)) {
1216*4882a593Smuzhiyun if (priv->pt_port)
1217*4882a593Smuzhiyun synaptics_pass_pt_packet(priv->pt_port,
1218*4882a593Smuzhiyun psmouse->packet);
1219*4882a593Smuzhiyun } else
1220*4882a593Smuzhiyun synaptics_process_packet(psmouse);
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun return PSMOUSE_FULL_PACKET;
1223*4882a593Smuzhiyun }
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun return synaptics_validate_byte(psmouse, psmouse->pktcnt - 1, priv->pkt_type) ?
1226*4882a593Smuzhiyun PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
1227*4882a593Smuzhiyun }
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun /*****************************************************************************
1230*4882a593Smuzhiyun * Driver initialization/cleanup functions
1231*4882a593Smuzhiyun ****************************************************************************/
set_abs_position_params(struct input_dev * dev,struct synaptics_device_info * info,int x_code,int y_code)1232*4882a593Smuzhiyun static void set_abs_position_params(struct input_dev *dev,
1233*4882a593Smuzhiyun struct synaptics_device_info *info,
1234*4882a593Smuzhiyun int x_code, int y_code)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun int x_min = info->x_min ?: XMIN_NOMINAL;
1237*4882a593Smuzhiyun int x_max = info->x_max ?: XMAX_NOMINAL;
1238*4882a593Smuzhiyun int y_min = info->y_min ?: YMIN_NOMINAL;
1239*4882a593Smuzhiyun int y_max = info->y_max ?: YMAX_NOMINAL;
1240*4882a593Smuzhiyun int fuzz = SYN_CAP_REDUCED_FILTERING(info->ext_cap_0c) ?
1241*4882a593Smuzhiyun SYN_REDUCED_FILTER_FUZZ : 0;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0);
1244*4882a593Smuzhiyun input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0);
1245*4882a593Smuzhiyun input_abs_set_res(dev, x_code, info->x_res);
1246*4882a593Smuzhiyun input_abs_set_res(dev, y_code, info->y_res);
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun
set_input_params(struct psmouse * psmouse,struct synaptics_data * priv)1249*4882a593Smuzhiyun static int set_input_params(struct psmouse *psmouse,
1250*4882a593Smuzhiyun struct synaptics_data *priv)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
1253*4882a593Smuzhiyun struct synaptics_device_info *info = &priv->info;
1254*4882a593Smuzhiyun int i;
1255*4882a593Smuzhiyun int error;
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun /* Reset default psmouse capabilities */
1258*4882a593Smuzhiyun __clear_bit(EV_REL, dev->evbit);
1259*4882a593Smuzhiyun bitmap_zero(dev->relbit, REL_CNT);
1260*4882a593Smuzhiyun bitmap_zero(dev->keybit, KEY_CNT);
1261*4882a593Smuzhiyun
1262*4882a593Smuzhiyun /* Things that apply to both modes */
1263*4882a593Smuzhiyun __set_bit(INPUT_PROP_POINTER, dev->propbit);
1264*4882a593Smuzhiyun
1265*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_LEFT);
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun /* Clickpads report only left button */
1268*4882a593Smuzhiyun if (!SYN_CAP_CLICKPAD(info->ext_cap_0c)) {
1269*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_RIGHT);
1270*4882a593Smuzhiyun if (SYN_CAP_MIDDLE_BUTTON(info->capabilities))
1271*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_MIDDLE);
1272*4882a593Smuzhiyun }
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyun if (!priv->absolute_mode) {
1275*4882a593Smuzhiyun /* Relative mode */
1276*4882a593Smuzhiyun input_set_capability(dev, EV_REL, REL_X);
1277*4882a593Smuzhiyun input_set_capability(dev, EV_REL, REL_Y);
1278*4882a593Smuzhiyun return 0;
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun /* Absolute mode */
1282*4882a593Smuzhiyun set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y);
1283*4882a593Smuzhiyun input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun if (cr48_profile_sensor)
1286*4882a593Smuzhiyun input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
1287*4882a593Smuzhiyun
1288*4882a593Smuzhiyun if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) {
1289*4882a593Smuzhiyun set_abs_position_params(dev, info,
1290*4882a593Smuzhiyun ABS_MT_POSITION_X, ABS_MT_POSITION_Y);
1291*4882a593Smuzhiyun /* Image sensors can report per-contact pressure */
1292*4882a593Smuzhiyun input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun error = input_mt_init_slots(dev, 2,
1295*4882a593Smuzhiyun INPUT_MT_POINTER | INPUT_MT_TRACK);
1296*4882a593Smuzhiyun if (error)
1297*4882a593Smuzhiyun return error;
1298*4882a593Smuzhiyun
1299*4882a593Smuzhiyun /* Image sensors can signal 4 and 5 finger clicks */
1300*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_TOOL_QUADTAP);
1301*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_TOOL_QUINTTAP);
1302*4882a593Smuzhiyun } else if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) {
1303*4882a593Smuzhiyun set_abs_position_params(dev, info,
1304*4882a593Smuzhiyun ABS_MT_POSITION_X, ABS_MT_POSITION_Y);
1305*4882a593Smuzhiyun /*
1306*4882a593Smuzhiyun * Profile sensor in CR-48 tracks contacts reasonably well,
1307*4882a593Smuzhiyun * other non-image sensors with AGM use semi-mt.
1308*4882a593Smuzhiyun */
1309*4882a593Smuzhiyun error = input_mt_init_slots(dev, 2,
1310*4882a593Smuzhiyun INPUT_MT_POINTER |
1311*4882a593Smuzhiyun (cr48_profile_sensor ?
1312*4882a593Smuzhiyun INPUT_MT_TRACK :
1313*4882a593Smuzhiyun INPUT_MT_SEMI_MT));
1314*4882a593Smuzhiyun if (error)
1315*4882a593Smuzhiyun return error;
1316*4882a593Smuzhiyun
1317*4882a593Smuzhiyun /*
1318*4882a593Smuzhiyun * For semi-mt devices we send ABS_X/Y ourselves instead of
1319*4882a593Smuzhiyun * input_mt_report_pointer_emulation. But
1320*4882a593Smuzhiyun * input_mt_init_slots() resets the fuzz to 0, leading to a
1321*4882a593Smuzhiyun * filtered ABS_MT_POSITION_X but an unfiltered ABS_X
1322*4882a593Smuzhiyun * position. Let's re-initialize ABS_X/Y here.
1323*4882a593Smuzhiyun */
1324*4882a593Smuzhiyun if (!cr48_profile_sensor)
1325*4882a593Smuzhiyun set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y);
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun if (SYN_CAP_PALMDETECT(info->capabilities))
1329*4882a593Smuzhiyun input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
1330*4882a593Smuzhiyun
1331*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_TOUCH);
1332*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_TOOL_FINGER);
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun if (synaptics_has_multifinger(priv)) {
1335*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_TOOL_DOUBLETAP);
1336*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_TOOL_TRIPLETAP);
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun if (SYN_CAP_FOUR_BUTTON(info->capabilities) ||
1340*4882a593Smuzhiyun SYN_CAP_MIDDLE_BUTTON(info->capabilities)) {
1341*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_FORWARD);
1342*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_BACK);
1343*4882a593Smuzhiyun }
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun if (!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10))
1346*4882a593Smuzhiyun for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(info->ext_cap); i++)
1347*4882a593Smuzhiyun input_set_capability(dev, EV_KEY, BTN_0 + i);
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun if (SYN_CAP_CLICKPAD(info->ext_cap_0c)) {
1350*4882a593Smuzhiyun __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
1351*4882a593Smuzhiyun if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
1352*4882a593Smuzhiyun !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10))
1353*4882a593Smuzhiyun __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);
1354*4882a593Smuzhiyun }
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun return 0;
1357*4882a593Smuzhiyun }
1358*4882a593Smuzhiyun
synaptics_show_disable_gesture(struct psmouse * psmouse,void * data,char * buf)1359*4882a593Smuzhiyun static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
1360*4882a593Smuzhiyun void *data, char *buf)
1361*4882a593Smuzhiyun {
1362*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
1363*4882a593Smuzhiyun
1364*4882a593Smuzhiyun return sprintf(buf, "%c\n", priv->disable_gesture ? '1' : '0');
1365*4882a593Smuzhiyun }
1366*4882a593Smuzhiyun
synaptics_set_disable_gesture(struct psmouse * psmouse,void * data,const char * buf,size_t len)1367*4882a593Smuzhiyun static ssize_t synaptics_set_disable_gesture(struct psmouse *psmouse,
1368*4882a593Smuzhiyun void *data, const char *buf,
1369*4882a593Smuzhiyun size_t len)
1370*4882a593Smuzhiyun {
1371*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
1372*4882a593Smuzhiyun unsigned int value;
1373*4882a593Smuzhiyun int err;
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun err = kstrtouint(buf, 10, &value);
1376*4882a593Smuzhiyun if (err)
1377*4882a593Smuzhiyun return err;
1378*4882a593Smuzhiyun
1379*4882a593Smuzhiyun if (value > 1)
1380*4882a593Smuzhiyun return -EINVAL;
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun if (value == priv->disable_gesture)
1383*4882a593Smuzhiyun return len;
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun priv->disable_gesture = value;
1386*4882a593Smuzhiyun if (value)
1387*4882a593Smuzhiyun priv->mode |= SYN_BIT_DISABLE_GESTURE;
1388*4882a593Smuzhiyun else
1389*4882a593Smuzhiyun priv->mode &= ~SYN_BIT_DISABLE_GESTURE;
1390*4882a593Smuzhiyun
1391*4882a593Smuzhiyun if (synaptics_mode_cmd(psmouse, priv->mode))
1392*4882a593Smuzhiyun return -EIO;
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun return len;
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL,
1398*4882a593Smuzhiyun synaptics_show_disable_gesture,
1399*4882a593Smuzhiyun synaptics_set_disable_gesture);
1400*4882a593Smuzhiyun
synaptics_disconnect(struct psmouse * psmouse)1401*4882a593Smuzhiyun static void synaptics_disconnect(struct psmouse *psmouse)
1402*4882a593Smuzhiyun {
1403*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun /*
1406*4882a593Smuzhiyun * We might have left a breadcrumb when trying to
1407*4882a593Smuzhiyun * set up SMbus companion.
1408*4882a593Smuzhiyun */
1409*4882a593Smuzhiyun psmouse_smbus_cleanup(psmouse);
1410*4882a593Smuzhiyun
1411*4882a593Smuzhiyun if (!priv->absolute_mode &&
1412*4882a593Smuzhiyun SYN_ID_DISGEST_SUPPORTED(priv->info.identity))
1413*4882a593Smuzhiyun device_remove_file(&psmouse->ps2dev.serio->dev,
1414*4882a593Smuzhiyun &psmouse_attr_disable_gesture.dattr);
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun synaptics_reset(psmouse);
1417*4882a593Smuzhiyun kfree(priv);
1418*4882a593Smuzhiyun psmouse->private = NULL;
1419*4882a593Smuzhiyun }
1420*4882a593Smuzhiyun
synaptics_reconnect(struct psmouse * psmouse)1421*4882a593Smuzhiyun static int synaptics_reconnect(struct psmouse *psmouse)
1422*4882a593Smuzhiyun {
1423*4882a593Smuzhiyun struct synaptics_data *priv = psmouse->private;
1424*4882a593Smuzhiyun struct synaptics_device_info info;
1425*4882a593Smuzhiyun u8 param[2];
1426*4882a593Smuzhiyun int retry = 0;
1427*4882a593Smuzhiyun int error;
1428*4882a593Smuzhiyun
1429*4882a593Smuzhiyun do {
1430*4882a593Smuzhiyun psmouse_reset(psmouse);
1431*4882a593Smuzhiyun if (retry) {
1432*4882a593Smuzhiyun /*
1433*4882a593Smuzhiyun * On some boxes, right after resuming, the touchpad
1434*4882a593Smuzhiyun * needs some time to finish initializing (I assume
1435*4882a593Smuzhiyun * it needs time to calibrate) and start responding
1436*4882a593Smuzhiyun * to Synaptics-specific queries, so let's wait a
1437*4882a593Smuzhiyun * bit.
1438*4882a593Smuzhiyun */
1439*4882a593Smuzhiyun ssleep(1);
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID);
1442*4882a593Smuzhiyun error = synaptics_detect(psmouse, 0);
1443*4882a593Smuzhiyun } while (error && ++retry < 3);
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun if (error)
1446*4882a593Smuzhiyun return error;
1447*4882a593Smuzhiyun
1448*4882a593Smuzhiyun if (retry > 1)
1449*4882a593Smuzhiyun psmouse_dbg(psmouse, "reconnected after %d tries\n", retry);
1450*4882a593Smuzhiyun
1451*4882a593Smuzhiyun error = synaptics_query_hardware(psmouse, &info);
1452*4882a593Smuzhiyun if (error) {
1453*4882a593Smuzhiyun psmouse_err(psmouse, "Unable to query device.\n");
1454*4882a593Smuzhiyun return error;
1455*4882a593Smuzhiyun }
1456*4882a593Smuzhiyun
1457*4882a593Smuzhiyun error = synaptics_set_mode(psmouse);
1458*4882a593Smuzhiyun if (error) {
1459*4882a593Smuzhiyun psmouse_err(psmouse, "Unable to initialize device.\n");
1460*4882a593Smuzhiyun return error;
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun if (info.identity != priv->info.identity ||
1464*4882a593Smuzhiyun info.model_id != priv->info.model_id ||
1465*4882a593Smuzhiyun info.capabilities != priv->info.capabilities ||
1466*4882a593Smuzhiyun info.ext_cap != priv->info.ext_cap) {
1467*4882a593Smuzhiyun psmouse_err(psmouse,
1468*4882a593Smuzhiyun "hardware appears to be different: id(%u-%u), model(%u-%u), caps(%x-%x), ext(%x-%x).\n",
1469*4882a593Smuzhiyun priv->info.identity, info.identity,
1470*4882a593Smuzhiyun priv->info.model_id, info.model_id,
1471*4882a593Smuzhiyun priv->info.capabilities, info.capabilities,
1472*4882a593Smuzhiyun priv->info.ext_cap, info.ext_cap);
1473*4882a593Smuzhiyun return -ENXIO;
1474*4882a593Smuzhiyun }
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun return 0;
1477*4882a593Smuzhiyun }
1478*4882a593Smuzhiyun
1479*4882a593Smuzhiyun static bool impaired_toshiba_kbc;
1480*4882a593Smuzhiyun
1481*4882a593Smuzhiyun static const struct dmi_system_id toshiba_dmi_table[] __initconst = {
1482*4882a593Smuzhiyun #if defined(CONFIG_DMI) && defined(CONFIG_X86)
1483*4882a593Smuzhiyun {
1484*4882a593Smuzhiyun /* Toshiba Satellite */
1485*4882a593Smuzhiyun .matches = {
1486*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1487*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
1488*4882a593Smuzhiyun },
1489*4882a593Smuzhiyun },
1490*4882a593Smuzhiyun {
1491*4882a593Smuzhiyun /* Toshiba Dynabook */
1492*4882a593Smuzhiyun .matches = {
1493*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1494*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"),
1495*4882a593Smuzhiyun },
1496*4882a593Smuzhiyun },
1497*4882a593Smuzhiyun {
1498*4882a593Smuzhiyun /* Toshiba Portege M300 */
1499*4882a593Smuzhiyun .matches = {
1500*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1501*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
1502*4882a593Smuzhiyun },
1503*4882a593Smuzhiyun
1504*4882a593Smuzhiyun },
1505*4882a593Smuzhiyun {
1506*4882a593Smuzhiyun /* Toshiba Portege M300 */
1507*4882a593Smuzhiyun .matches = {
1508*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1509*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"),
1510*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"),
1511*4882a593Smuzhiyun },
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun },
1514*4882a593Smuzhiyun #endif
1515*4882a593Smuzhiyun { }
1516*4882a593Smuzhiyun };
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun static bool broken_olpc_ec;
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun static const struct dmi_system_id olpc_dmi_table[] __initconst = {
1521*4882a593Smuzhiyun #if defined(CONFIG_DMI) && defined(CONFIG_OLPC)
1522*4882a593Smuzhiyun {
1523*4882a593Smuzhiyun /* OLPC XO-1 or XO-1.5 */
1524*4882a593Smuzhiyun .matches = {
1525*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
1526*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
1527*4882a593Smuzhiyun },
1528*4882a593Smuzhiyun },
1529*4882a593Smuzhiyun #endif
1530*4882a593Smuzhiyun { }
1531*4882a593Smuzhiyun };
1532*4882a593Smuzhiyun
1533*4882a593Smuzhiyun static const struct dmi_system_id __initconst cr48_dmi_table[] = {
1534*4882a593Smuzhiyun #if defined(CONFIG_DMI) && defined(CONFIG_X86)
1535*4882a593Smuzhiyun {
1536*4882a593Smuzhiyun /* Cr-48 Chromebook (Codename Mario) */
1537*4882a593Smuzhiyun .matches = {
1538*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "IEC"),
1539*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
1540*4882a593Smuzhiyun },
1541*4882a593Smuzhiyun },
1542*4882a593Smuzhiyun #endif
1543*4882a593Smuzhiyun { }
1544*4882a593Smuzhiyun };
1545*4882a593Smuzhiyun
synaptics_module_init(void)1546*4882a593Smuzhiyun void __init synaptics_module_init(void)
1547*4882a593Smuzhiyun {
1548*4882a593Smuzhiyun impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
1549*4882a593Smuzhiyun broken_olpc_ec = dmi_check_system(olpc_dmi_table);
1550*4882a593Smuzhiyun cr48_profile_sensor = dmi_check_system(cr48_dmi_table);
1551*4882a593Smuzhiyun }
1552*4882a593Smuzhiyun
synaptics_init_ps2(struct psmouse * psmouse,struct synaptics_device_info * info,bool absolute_mode)1553*4882a593Smuzhiyun static int synaptics_init_ps2(struct psmouse *psmouse,
1554*4882a593Smuzhiyun struct synaptics_device_info *info,
1555*4882a593Smuzhiyun bool absolute_mode)
1556*4882a593Smuzhiyun {
1557*4882a593Smuzhiyun struct synaptics_data *priv;
1558*4882a593Smuzhiyun int err;
1559*4882a593Smuzhiyun
1560*4882a593Smuzhiyun synaptics_apply_quirks(psmouse, info);
1561*4882a593Smuzhiyun
1562*4882a593Smuzhiyun psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
1563*4882a593Smuzhiyun if (!priv)
1564*4882a593Smuzhiyun return -ENOMEM;
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun priv->info = *info;
1567*4882a593Smuzhiyun priv->absolute_mode = absolute_mode;
1568*4882a593Smuzhiyun if (SYN_ID_DISGEST_SUPPORTED(info->identity))
1569*4882a593Smuzhiyun priv->disable_gesture = true;
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun /*
1572*4882a593Smuzhiyun * Unfortunately ForcePad capability is not exported over PS/2,
1573*4882a593Smuzhiyun * so we have to resort to checking PNP IDs.
1574*4882a593Smuzhiyun */
1575*4882a593Smuzhiyun priv->is_forcepad = psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids);
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun err = synaptics_set_mode(psmouse);
1578*4882a593Smuzhiyun if (err) {
1579*4882a593Smuzhiyun psmouse_err(psmouse, "Unable to initialize device.\n");
1580*4882a593Smuzhiyun goto init_fail;
1581*4882a593Smuzhiyun }
1582*4882a593Smuzhiyun
1583*4882a593Smuzhiyun priv->pkt_type = SYN_MODEL_NEWABS(info->model_id) ?
1584*4882a593Smuzhiyun SYN_NEWABS : SYN_OLDABS;
1585*4882a593Smuzhiyun
1586*4882a593Smuzhiyun psmouse_info(psmouse,
1587*4882a593Smuzhiyun "Touchpad model: %lu, fw: %lu.%lu, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n",
1588*4882a593Smuzhiyun SYN_ID_MODEL(info->identity),
1589*4882a593Smuzhiyun SYN_ID_MAJOR(info->identity), SYN_ID_MINOR(info->identity),
1590*4882a593Smuzhiyun info->model_id,
1591*4882a593Smuzhiyun info->capabilities, info->ext_cap, info->ext_cap_0c,
1592*4882a593Smuzhiyun info->ext_cap_10, info->board_id, info->firmware_id);
1593*4882a593Smuzhiyun
1594*4882a593Smuzhiyun err = set_input_params(psmouse, priv);
1595*4882a593Smuzhiyun if (err) {
1596*4882a593Smuzhiyun psmouse_err(psmouse,
1597*4882a593Smuzhiyun "failed to set up capabilities: %d\n", err);
1598*4882a593Smuzhiyun goto init_fail;
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun
1601*4882a593Smuzhiyun /*
1602*4882a593Smuzhiyun * Encode touchpad model so that it can be used to set
1603*4882a593Smuzhiyun * input device->id.version and be visible to userspace.
1604*4882a593Smuzhiyun * Because version is __u16 we have to drop something.
1605*4882a593Smuzhiyun * Hardware info bits seem to be good candidates as they
1606*4882a593Smuzhiyun * are documented to be for Synaptics corp. internal use.
1607*4882a593Smuzhiyun */
1608*4882a593Smuzhiyun psmouse->model = ((info->model_id & 0x00ff0000) >> 8) |
1609*4882a593Smuzhiyun (info->model_id & 0x000000ff);
1610*4882a593Smuzhiyun
1611*4882a593Smuzhiyun if (absolute_mode) {
1612*4882a593Smuzhiyun psmouse->protocol_handler = synaptics_process_byte;
1613*4882a593Smuzhiyun psmouse->pktsize = 6;
1614*4882a593Smuzhiyun } else {
1615*4882a593Smuzhiyun /* Relative mode follows standard PS/2 mouse protocol */
1616*4882a593Smuzhiyun psmouse->protocol_handler = psmouse_process_byte;
1617*4882a593Smuzhiyun psmouse->pktsize = 3;
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun psmouse->set_rate = synaptics_set_rate;
1621*4882a593Smuzhiyun psmouse->disconnect = synaptics_disconnect;
1622*4882a593Smuzhiyun psmouse->reconnect = synaptics_reconnect;
1623*4882a593Smuzhiyun psmouse->cleanup = synaptics_reset;
1624*4882a593Smuzhiyun /* Synaptics can usually stay in sync without extra help */
1625*4882a593Smuzhiyun psmouse->resync_time = 0;
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun if (SYN_CAP_PASS_THROUGH(info->capabilities))
1628*4882a593Smuzhiyun synaptics_pt_create(psmouse);
1629*4882a593Smuzhiyun
1630*4882a593Smuzhiyun /*
1631*4882a593Smuzhiyun * Toshiba's KBC seems to have trouble handling data from
1632*4882a593Smuzhiyun * Synaptics at full rate. Switch to a lower rate (roughly
1633*4882a593Smuzhiyun * the same rate as a standard PS/2 mouse).
1634*4882a593Smuzhiyun */
1635*4882a593Smuzhiyun if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
1636*4882a593Smuzhiyun psmouse_info(psmouse,
1637*4882a593Smuzhiyun "Toshiba %s detected, limiting rate to 40pps.\n",
1638*4882a593Smuzhiyun dmi_get_system_info(DMI_PRODUCT_NAME));
1639*4882a593Smuzhiyun psmouse->rate = 40;
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(info->identity)) {
1643*4882a593Smuzhiyun err = device_create_file(&psmouse->ps2dev.serio->dev,
1644*4882a593Smuzhiyun &psmouse_attr_disable_gesture.dattr);
1645*4882a593Smuzhiyun if (err) {
1646*4882a593Smuzhiyun psmouse_err(psmouse,
1647*4882a593Smuzhiyun "Failed to create disable_gesture attribute (%d)",
1648*4882a593Smuzhiyun err);
1649*4882a593Smuzhiyun goto init_fail;
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun }
1652*4882a593Smuzhiyun
1653*4882a593Smuzhiyun return 0;
1654*4882a593Smuzhiyun
1655*4882a593Smuzhiyun init_fail:
1656*4882a593Smuzhiyun kfree(priv);
1657*4882a593Smuzhiyun return err;
1658*4882a593Smuzhiyun }
1659*4882a593Smuzhiyun
__synaptics_init(struct psmouse * psmouse,bool absolute_mode)1660*4882a593Smuzhiyun static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
1661*4882a593Smuzhiyun {
1662*4882a593Smuzhiyun struct synaptics_device_info info;
1663*4882a593Smuzhiyun int error;
1664*4882a593Smuzhiyun
1665*4882a593Smuzhiyun psmouse_reset(psmouse);
1666*4882a593Smuzhiyun
1667*4882a593Smuzhiyun error = synaptics_query_hardware(psmouse, &info);
1668*4882a593Smuzhiyun if (error) {
1669*4882a593Smuzhiyun psmouse_err(psmouse, "Unable to query device: %d\n", error);
1670*4882a593Smuzhiyun return error;
1671*4882a593Smuzhiyun }
1672*4882a593Smuzhiyun
1673*4882a593Smuzhiyun return synaptics_init_ps2(psmouse, &info, absolute_mode);
1674*4882a593Smuzhiyun }
1675*4882a593Smuzhiyun
synaptics_init_absolute(struct psmouse * psmouse)1676*4882a593Smuzhiyun int synaptics_init_absolute(struct psmouse *psmouse)
1677*4882a593Smuzhiyun {
1678*4882a593Smuzhiyun return __synaptics_init(psmouse, true);
1679*4882a593Smuzhiyun }
1680*4882a593Smuzhiyun
synaptics_init_relative(struct psmouse * psmouse)1681*4882a593Smuzhiyun int synaptics_init_relative(struct psmouse *psmouse)
1682*4882a593Smuzhiyun {
1683*4882a593Smuzhiyun return __synaptics_init(psmouse, false);
1684*4882a593Smuzhiyun }
1685*4882a593Smuzhiyun
synaptics_setup_ps2(struct psmouse * psmouse,struct synaptics_device_info * info)1686*4882a593Smuzhiyun static int synaptics_setup_ps2(struct psmouse *psmouse,
1687*4882a593Smuzhiyun struct synaptics_device_info *info)
1688*4882a593Smuzhiyun {
1689*4882a593Smuzhiyun bool absolute_mode = true;
1690*4882a593Smuzhiyun int error;
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun /*
1693*4882a593Smuzhiyun * The OLPC XO has issues with Synaptics' absolute mode; the constant
1694*4882a593Smuzhiyun * packet spew overloads the EC such that key presses on the keyboard
1695*4882a593Smuzhiyun * are missed. Given that, don't even attempt to use Absolute mode.
1696*4882a593Smuzhiyun * Relative mode seems to work just fine.
1697*4882a593Smuzhiyun */
1698*4882a593Smuzhiyun if (broken_olpc_ec) {
1699*4882a593Smuzhiyun psmouse_info(psmouse,
1700*4882a593Smuzhiyun "OLPC XO detected, forcing relative protocol.\n");
1701*4882a593Smuzhiyun absolute_mode = false;
1702*4882a593Smuzhiyun }
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun error = synaptics_init_ps2(psmouse, info, absolute_mode);
1705*4882a593Smuzhiyun if (error)
1706*4882a593Smuzhiyun return error;
1707*4882a593Smuzhiyun
1708*4882a593Smuzhiyun return absolute_mode ? PSMOUSE_SYNAPTICS : PSMOUSE_SYNAPTICS_RELATIVE;
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun #else /* CONFIG_MOUSE_PS2_SYNAPTICS */
1712*4882a593Smuzhiyun
synaptics_module_init(void)1713*4882a593Smuzhiyun void __init synaptics_module_init(void)
1714*4882a593Smuzhiyun {
1715*4882a593Smuzhiyun }
1716*4882a593Smuzhiyun
1717*4882a593Smuzhiyun static int __maybe_unused
synaptics_setup_ps2(struct psmouse * psmouse,struct synaptics_device_info * info)1718*4882a593Smuzhiyun synaptics_setup_ps2(struct psmouse *psmouse,
1719*4882a593Smuzhiyun struct synaptics_device_info *info)
1720*4882a593Smuzhiyun {
1721*4882a593Smuzhiyun return -ENOSYS;
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun
1724*4882a593Smuzhiyun #endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
1725*4882a593Smuzhiyun
1726*4882a593Smuzhiyun #ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS
1727*4882a593Smuzhiyun
1728*4882a593Smuzhiyun /*
1729*4882a593Smuzhiyun * The newest Synaptics device can use a secondary bus (called InterTouch) which
1730*4882a593Smuzhiyun * provides a better bandwidth and allow a better control of the touchpads.
1731*4882a593Smuzhiyun * This is used to decide if we need to use this bus or not.
1732*4882a593Smuzhiyun */
1733*4882a593Smuzhiyun enum {
1734*4882a593Smuzhiyun SYNAPTICS_INTERTOUCH_NOT_SET = -1,
1735*4882a593Smuzhiyun SYNAPTICS_INTERTOUCH_OFF,
1736*4882a593Smuzhiyun SYNAPTICS_INTERTOUCH_ON,
1737*4882a593Smuzhiyun };
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun static int synaptics_intertouch = IS_ENABLED(CONFIG_RMI4_SMB) ?
1740*4882a593Smuzhiyun SYNAPTICS_INTERTOUCH_NOT_SET : SYNAPTICS_INTERTOUCH_OFF;
1741*4882a593Smuzhiyun module_param_named(synaptics_intertouch, synaptics_intertouch, int, 0644);
1742*4882a593Smuzhiyun MODULE_PARM_DESC(synaptics_intertouch, "Use a secondary bus for the Synaptics device.");
1743*4882a593Smuzhiyun
synaptics_create_intertouch(struct psmouse * psmouse,struct synaptics_device_info * info,bool leave_breadcrumbs)1744*4882a593Smuzhiyun static int synaptics_create_intertouch(struct psmouse *psmouse,
1745*4882a593Smuzhiyun struct synaptics_device_info *info,
1746*4882a593Smuzhiyun bool leave_breadcrumbs)
1747*4882a593Smuzhiyun {
1748*4882a593Smuzhiyun bool topbuttonpad =
1749*4882a593Smuzhiyun psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
1750*4882a593Smuzhiyun !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10);
1751*4882a593Smuzhiyun const struct rmi_device_platform_data pdata = {
1752*4882a593Smuzhiyun .sensor_pdata = {
1753*4882a593Smuzhiyun .sensor_type = rmi_sensor_touchpad,
1754*4882a593Smuzhiyun .axis_align.flip_y = true,
1755*4882a593Smuzhiyun .kernel_tracking = false,
1756*4882a593Smuzhiyun .topbuttonpad = topbuttonpad,
1757*4882a593Smuzhiyun },
1758*4882a593Smuzhiyun .gpio_data = {
1759*4882a593Smuzhiyun .buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c),
1760*4882a593Smuzhiyun .trackstick_buttons =
1761*4882a593Smuzhiyun !!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10),
1762*4882a593Smuzhiyun },
1763*4882a593Smuzhiyun };
1764*4882a593Smuzhiyun const struct i2c_board_info intertouch_board = {
1765*4882a593Smuzhiyun I2C_BOARD_INFO("rmi4_smbus", 0x2c),
1766*4882a593Smuzhiyun .flags = I2C_CLIENT_HOST_NOTIFY,
1767*4882a593Smuzhiyun };
1768*4882a593Smuzhiyun
1769*4882a593Smuzhiyun return psmouse_smbus_init(psmouse, &intertouch_board,
1770*4882a593Smuzhiyun &pdata, sizeof(pdata), true,
1771*4882a593Smuzhiyun leave_breadcrumbs);
1772*4882a593Smuzhiyun }
1773*4882a593Smuzhiyun
1774*4882a593Smuzhiyun /**
1775*4882a593Smuzhiyun * synaptics_setup_intertouch - called once the PS/2 devices are enumerated
1776*4882a593Smuzhiyun * and decides to instantiate a SMBus InterTouch device.
1777*4882a593Smuzhiyun */
synaptics_setup_intertouch(struct psmouse * psmouse,struct synaptics_device_info * info,bool leave_breadcrumbs)1778*4882a593Smuzhiyun static int synaptics_setup_intertouch(struct psmouse *psmouse,
1779*4882a593Smuzhiyun struct synaptics_device_info *info,
1780*4882a593Smuzhiyun bool leave_breadcrumbs)
1781*4882a593Smuzhiyun {
1782*4882a593Smuzhiyun int error;
1783*4882a593Smuzhiyun
1784*4882a593Smuzhiyun if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_OFF)
1785*4882a593Smuzhiyun return -ENXIO;
1786*4882a593Smuzhiyun
1787*4882a593Smuzhiyun if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_NOT_SET) {
1788*4882a593Smuzhiyun if (!psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
1789*4882a593Smuzhiyun !psmouse_matches_pnp_id(psmouse, smbus_pnp_ids)) {
1790*4882a593Smuzhiyun
1791*4882a593Smuzhiyun if (!psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids))
1792*4882a593Smuzhiyun psmouse_info(psmouse,
1793*4882a593Smuzhiyun "Your touchpad (%s) says it can support a different bus. "
1794*4882a593Smuzhiyun "If i2c-hid and hid-rmi are not used, you might want to try setting psmouse.synaptics_intertouch to 1 and report this to linux-input@vger.kernel.org.\n",
1795*4882a593Smuzhiyun psmouse->ps2dev.serio->firmware_id);
1796*4882a593Smuzhiyun
1797*4882a593Smuzhiyun return -ENXIO;
1798*4882a593Smuzhiyun }
1799*4882a593Smuzhiyun }
1800*4882a593Smuzhiyun
1801*4882a593Smuzhiyun psmouse_info(psmouse, "Trying to set up SMBus access\n");
1802*4882a593Smuzhiyun
1803*4882a593Smuzhiyun error = synaptics_create_intertouch(psmouse, info, leave_breadcrumbs);
1804*4882a593Smuzhiyun if (error) {
1805*4882a593Smuzhiyun if (error == -EAGAIN)
1806*4882a593Smuzhiyun psmouse_info(psmouse, "SMbus companion is not ready yet\n");
1807*4882a593Smuzhiyun else
1808*4882a593Smuzhiyun psmouse_err(psmouse, "unable to create intertouch device\n");
1809*4882a593Smuzhiyun
1810*4882a593Smuzhiyun return error;
1811*4882a593Smuzhiyun }
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun return 0;
1814*4882a593Smuzhiyun }
1815*4882a593Smuzhiyun
synaptics_init_smbus(struct psmouse * psmouse)1816*4882a593Smuzhiyun int synaptics_init_smbus(struct psmouse *psmouse)
1817*4882a593Smuzhiyun {
1818*4882a593Smuzhiyun struct synaptics_device_info info;
1819*4882a593Smuzhiyun int error;
1820*4882a593Smuzhiyun
1821*4882a593Smuzhiyun psmouse_reset(psmouse);
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun error = synaptics_query_hardware(psmouse, &info);
1824*4882a593Smuzhiyun if (error) {
1825*4882a593Smuzhiyun psmouse_err(psmouse, "Unable to query device: %d\n", error);
1826*4882a593Smuzhiyun return error;
1827*4882a593Smuzhiyun }
1828*4882a593Smuzhiyun
1829*4882a593Smuzhiyun if (!SYN_CAP_INTERTOUCH(info.ext_cap_0c))
1830*4882a593Smuzhiyun return -ENXIO;
1831*4882a593Smuzhiyun
1832*4882a593Smuzhiyun return synaptics_create_intertouch(psmouse, &info, false);
1833*4882a593Smuzhiyun }
1834*4882a593Smuzhiyun
1835*4882a593Smuzhiyun #else /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */
1836*4882a593Smuzhiyun
1837*4882a593Smuzhiyun static int __maybe_unused
synaptics_setup_intertouch(struct psmouse * psmouse,struct synaptics_device_info * info,bool leave_breadcrumbs)1838*4882a593Smuzhiyun synaptics_setup_intertouch(struct psmouse *psmouse,
1839*4882a593Smuzhiyun struct synaptics_device_info *info,
1840*4882a593Smuzhiyun bool leave_breadcrumbs)
1841*4882a593Smuzhiyun {
1842*4882a593Smuzhiyun return -ENOSYS;
1843*4882a593Smuzhiyun }
1844*4882a593Smuzhiyun
synaptics_init_smbus(struct psmouse * psmouse)1845*4882a593Smuzhiyun int synaptics_init_smbus(struct psmouse *psmouse)
1846*4882a593Smuzhiyun {
1847*4882a593Smuzhiyun return -ENOSYS;
1848*4882a593Smuzhiyun }
1849*4882a593Smuzhiyun
1850*4882a593Smuzhiyun #endif /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */
1851*4882a593Smuzhiyun
1852*4882a593Smuzhiyun #if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \
1853*4882a593Smuzhiyun defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)
1854*4882a593Smuzhiyun
synaptics_init(struct psmouse * psmouse)1855*4882a593Smuzhiyun int synaptics_init(struct psmouse *psmouse)
1856*4882a593Smuzhiyun {
1857*4882a593Smuzhiyun struct synaptics_device_info info;
1858*4882a593Smuzhiyun int error;
1859*4882a593Smuzhiyun int retval;
1860*4882a593Smuzhiyun
1861*4882a593Smuzhiyun psmouse_reset(psmouse);
1862*4882a593Smuzhiyun
1863*4882a593Smuzhiyun error = synaptics_query_hardware(psmouse, &info);
1864*4882a593Smuzhiyun if (error) {
1865*4882a593Smuzhiyun psmouse_err(psmouse, "Unable to query device: %d\n", error);
1866*4882a593Smuzhiyun return error;
1867*4882a593Smuzhiyun }
1868*4882a593Smuzhiyun
1869*4882a593Smuzhiyun if (SYN_CAP_INTERTOUCH(info.ext_cap_0c)) {
1870*4882a593Smuzhiyun if ((!IS_ENABLED(CONFIG_RMI4_SMB) ||
1871*4882a593Smuzhiyun !IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)) &&
1872*4882a593Smuzhiyun /* Forcepads need F21, which is not ready */
1873*4882a593Smuzhiyun !psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids)) {
1874*4882a593Smuzhiyun psmouse_warn(psmouse,
1875*4882a593Smuzhiyun "The touchpad can support a better bus than the too old PS/2 protocol. "
1876*4882a593Smuzhiyun "Make sure MOUSE_PS2_SYNAPTICS_SMBUS and RMI4_SMB are enabled to get a better touchpad experience.\n");
1877*4882a593Smuzhiyun }
1878*4882a593Smuzhiyun
1879*4882a593Smuzhiyun error = synaptics_setup_intertouch(psmouse, &info, true);
1880*4882a593Smuzhiyun if (!error)
1881*4882a593Smuzhiyun return PSMOUSE_SYNAPTICS_SMBUS;
1882*4882a593Smuzhiyun }
1883*4882a593Smuzhiyun
1884*4882a593Smuzhiyun retval = synaptics_setup_ps2(psmouse, &info);
1885*4882a593Smuzhiyun if (retval < 0) {
1886*4882a593Smuzhiyun /*
1887*4882a593Smuzhiyun * Not using any flavor of Synaptics support, so clean up
1888*4882a593Smuzhiyun * SMbus breadcrumbs, if any.
1889*4882a593Smuzhiyun */
1890*4882a593Smuzhiyun psmouse_smbus_cleanup(psmouse);
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun return retval;
1894*4882a593Smuzhiyun }
1895*4882a593Smuzhiyun
1896*4882a593Smuzhiyun #else /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */
1897*4882a593Smuzhiyun
synaptics_init(struct psmouse * psmouse)1898*4882a593Smuzhiyun int synaptics_init(struct psmouse *psmouse)
1899*4882a593Smuzhiyun {
1900*4882a593Smuzhiyun return -ENOSYS;
1901*4882a593Smuzhiyun }
1902*4882a593Smuzhiyun
1903*4882a593Smuzhiyun #endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */
1904