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