Branch data Line data Source code
1 : : /*
2 : : * Synaptics TouchPad PS/2 mouse driver
3 : : *
4 : : * 2003 Dmitry Torokhov <dtor@mail.ru>
5 : : * Added support for pass-through port. Special thanks to Peter Berg Larsen
6 : : * for explaining various Synaptics quirks.
7 : : *
8 : : * 2003 Peter Osterlund <petero2@telia.com>
9 : : * Ported to 2.5 input device infrastructure.
10 : : *
11 : : * Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
12 : : * start merging tpconfig and gpm code to a xfree-input module
13 : : * adding some changes and extensions (ex. 3rd and 4th button)
14 : : *
15 : : * Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
16 : : * Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
17 : : * code for the special synaptics commands (from the tpconfig-source)
18 : : *
19 : : * This program is free software; you can redistribute it and/or modify it
20 : : * under the terms of the GNU General Public License version 2 as published by
21 : : * the Free Software Foundation.
22 : : *
23 : : * Trademarks are the property of their respective owners.
24 : : */
25 : :
26 : : #include <linux/module.h>
27 : : #include <linux/delay.h>
28 : : #include <linux/dmi.h>
29 : : #include <linux/input/mt.h>
30 : : #include <linux/serio.h>
31 : : #include <linux/libps2.h>
32 : : #include <linux/slab.h>
33 : : #include "psmouse.h"
34 : : #include "synaptics.h"
35 : :
36 : : /*
37 : : * The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
38 : : * section 2.3.2, which says that they should be valid regardless of the
39 : : * actual size of the sensor.
40 : : * Note that newer firmware allows querying device for maximum useable
41 : : * coordinates.
42 : : */
43 : : #define XMIN 0
44 : : #define XMAX 6143
45 : : #define YMIN 0
46 : : #define YMAX 6143
47 : : #define XMIN_NOMINAL 1472
48 : : #define XMAX_NOMINAL 5472
49 : : #define YMIN_NOMINAL 1408
50 : : #define YMAX_NOMINAL 4448
51 : :
52 : : /* Size in bits of absolute position values reported by the hardware */
53 : : #define ABS_POS_BITS 13
54 : :
55 : : /*
56 : : * These values should represent the absolute maximum value that will
57 : : * be reported for a positive position value. Some Synaptics firmware
58 : : * uses this value to indicate a finger near the edge of the touchpad
59 : : * whose precise position cannot be determined.
60 : : *
61 : : * At least one touchpad is known to report positions in excess of this
62 : : * value which are actually negative values truncated to the 13-bit
63 : : * reporting range. These values have never been observed to be lower
64 : : * than 8184 (i.e. -8), so we treat all values greater than 8176 as
65 : : * negative and any other value as positive.
66 : : */
67 : : #define X_MAX_POSITIVE 8176
68 : : #define Y_MAX_POSITIVE 8176
69 : :
70 : : /*****************************************************************************
71 : : * Stuff we need even when we do not want native Synaptics support
72 : : ****************************************************************************/
73 : :
74 : : /*
75 : : * Set the synaptics touchpad mode byte by special commands
76 : : */
77 : 0 : static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
78 : : {
79 : : unsigned char param[1];
80 : :
81 [ # # ]: 0 : if (psmouse_sliced_command(psmouse, mode))
82 : : return -1;
83 : 0 : param[0] = SYN_PS_SET_MODE2;
84 [ # # ]: 0 : if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
85 : : return -1;
86 : 0 : return 0;
87 : : }
88 : :
89 : 0 : int synaptics_detect(struct psmouse *psmouse, bool set_properties)
90 : : {
91 : 0 : struct ps2dev *ps2dev = &psmouse->ps2dev;
92 : : unsigned char param[4];
93 : :
94 : 0 : param[0] = 0;
95 : :
96 : 0 : ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
97 : 0 : ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
98 : 0 : ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
99 : 0 : ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
100 : 0 : ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
101 : :
102 [ # # ]: 0 : if (param[1] != 0x47)
103 : : return -ENODEV;
104 : :
105 [ # # ]: 0 : if (set_properties) {
106 : 0 : psmouse->vendor = "Synaptics";
107 : 0 : psmouse->name = "TouchPad";
108 : : }
109 : :
110 : : return 0;
111 : : }
112 : :
113 : 0 : void synaptics_reset(struct psmouse *psmouse)
114 : : {
115 : : /* reset touchpad back to relative mode, gestures enabled */
116 : 0 : synaptics_mode_cmd(psmouse, 0);
117 : 0 : }
118 : :
119 : : #ifdef CONFIG_MOUSE_PS2_SYNAPTICS
120 : :
121 : : /*****************************************************************************
122 : : * Synaptics communications functions
123 : : ****************************************************************************/
124 : :
125 : : /*
126 : : * Synaptics touchpads report the y coordinate from bottom to top, which is
127 : : * opposite from what userspace expects.
128 : : * This function is used to invert y before reporting.
129 : : */
130 : : static int synaptics_invert_y(int y)
131 : : {
132 : 0 : return YMAX_NOMINAL + YMIN_NOMINAL - y;
133 : : }
134 : :
135 : : /*
136 : : * Send a command to the synpatics touchpad by special commands
137 : : */
138 : 0 : static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
139 : : {
140 [ # # ]: 0 : if (psmouse_sliced_command(psmouse, c))
141 : : return -1;
142 [ # # ]: 0 : if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
143 : : return -1;
144 : 0 : return 0;
145 : : }
146 : :
147 : : /*
148 : : * Read the model-id bytes from the touchpad
149 : : * see also SYN_MODEL_* macros
150 : : */
151 : 0 : static int synaptics_model_id(struct psmouse *psmouse)
152 : : {
153 : 0 : struct synaptics_data *priv = psmouse->private;
154 : : unsigned char mi[3];
155 : :
156 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
157 : : return -1;
158 : 0 : priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
159 : 0 : return 0;
160 : : }
161 : :
162 : : /*
163 : : * Read the board id from the touchpad
164 : : * The board id is encoded in the "QUERY MODES" response
165 : : */
166 : 0 : static int synaptics_board_id(struct psmouse *psmouse)
167 : : {
168 : 0 : struct synaptics_data *priv = psmouse->private;
169 : : unsigned char bid[3];
170 : :
171 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid))
172 : : return -1;
173 : 0 : priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1];
174 : 0 : return 0;
175 : : }
176 : :
177 : : /*
178 : : * Read the firmware id from the touchpad
179 : : */
180 : 0 : static int synaptics_firmware_id(struct psmouse *psmouse)
181 : : {
182 : 0 : struct synaptics_data *priv = psmouse->private;
183 : : unsigned char fwid[3];
184 : :
185 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid))
186 : : return -1;
187 : 0 : priv->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2];
188 : 0 : return 0;
189 : : }
190 : :
191 : : /*
192 : : * Read the capability-bits from the touchpad
193 : : * see also the SYN_CAP_* macros
194 : : */
195 : 0 : static int synaptics_capability(struct psmouse *psmouse)
196 : : {
197 : 0 : struct synaptics_data *priv = psmouse->private;
198 : : unsigned char cap[3];
199 : :
200 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
201 : : return -1;
202 : 0 : priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
203 : 0 : priv->ext_cap = priv->ext_cap_0c = 0;
204 : :
205 : : /*
206 : : * Older firmwares had submodel ID fixed to 0x47
207 : : */
208 [ # # ][ # # ]: 0 : if (SYN_ID_FULL(priv->identity) < 0x705 &&
209 : 0 : SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) {
210 : : return -1;
211 : : }
212 : :
213 : : /*
214 : : * Unless capExtended is set the rest of the flags should be ignored
215 : : */
216 [ # # ]: 0 : if (!SYN_CAP_EXTENDED(priv->capabilities))
217 : 0 : priv->capabilities = 0;
218 : :
219 [ # # ]: 0 : if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
220 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
221 : 0 : psmouse_warn(psmouse,
222 : : "device claims to have extended capabilities, but I'm not able to read them.\n");
223 : : } else {
224 : 0 : priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
225 : :
226 : : /*
227 : : * if nExtBtn is greater than 8 it should be considered
228 : : * invalid and treated as 0
229 : : */
230 [ # # ]: 0 : if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8)
231 : 0 : priv->ext_cap &= 0xff0fff;
232 : : }
233 : : }
234 : :
235 [ # # ]: 0 : if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
236 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
237 : 0 : psmouse_warn(psmouse,
238 : : "device claims to have extended capability 0x0c, but I'm not able to read it.\n");
239 : : } else {
240 : 0 : priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
241 : : }
242 : : }
243 : :
244 : : return 0;
245 : : }
246 : :
247 : : /*
248 : : * Identify Touchpad
249 : : * See also the SYN_ID_* macros
250 : : */
251 : 0 : static int synaptics_identify(struct psmouse *psmouse)
252 : : {
253 : 0 : struct synaptics_data *priv = psmouse->private;
254 : : unsigned char id[3];
255 : :
256 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
257 : : return -1;
258 : 0 : priv->identity = (id[0]<<16) | (id[1]<<8) | id[2];
259 [ # # ]: 0 : if (SYN_ID_IS_SYNAPTICS(priv->identity))
260 : : return 0;
261 : 0 : return -1;
262 : : }
263 : :
264 : : /*
265 : : * Read touchpad resolution and maximum reported coordinates
266 : : * Resolution is left zero if touchpad does not support the query
267 : : */
268 : :
269 : : static const int *quirk_min_max;
270 : :
271 : 0 : static int synaptics_resolution(struct psmouse *psmouse)
272 : : {
273 : 0 : struct synaptics_data *priv = psmouse->private;
274 : : unsigned char resp[3];
275 : :
276 [ # # ]: 0 : if (quirk_min_max) {
277 : 0 : priv->x_min = quirk_min_max[0];
278 : 0 : priv->x_max = quirk_min_max[1];
279 : 0 : priv->y_min = quirk_min_max[2];
280 : 0 : priv->y_max = quirk_min_max[3];
281 : 0 : return 0;
282 : : }
283 : :
284 [ # # ]: 0 : if (SYN_ID_MAJOR(priv->identity) < 4)
285 : : return 0;
286 : :
287 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) {
288 [ # # ][ # # ]: 0 : if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) {
[ # # ]
289 : 0 : priv->x_res = resp[0]; /* x resolution in units/mm */
290 : 0 : priv->y_res = resp[2]; /* y resolution in units/mm */
291 : : }
292 : : }
293 : :
294 [ # # ][ # # ]: 0 : if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&
295 : 0 : SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {
296 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) {
297 : 0 : psmouse_warn(psmouse,
298 : : "device claims to have max coordinates query, but I'm not able to read it.\n");
299 : : } else {
300 : 0 : priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
301 : 0 : priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
302 : : }
303 : : }
304 : :
305 [ # # ][ # # ]: 0 : if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 &&
306 : 0 : SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) {
307 [ # # ]: 0 : if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) {
308 : 0 : psmouse_warn(psmouse,
309 : : "device claims to have min coordinates query, but I'm not able to read it.\n");
310 : : } else {
311 : 0 : priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1);
312 : 0 : priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3);
313 : : }
314 : : }
315 : :
316 : : return 0;
317 : : }
318 : :
319 : 0 : static int synaptics_query_hardware(struct psmouse *psmouse)
320 : : {
321 [ # # ]: 0 : if (synaptics_identify(psmouse))
322 : : return -1;
323 [ # # ]: 0 : if (synaptics_model_id(psmouse))
324 : : return -1;
325 [ # # ]: 0 : if (synaptics_firmware_id(psmouse))
326 : : return -1;
327 [ # # ]: 0 : if (synaptics_board_id(psmouse))
328 : : return -1;
329 [ # # ]: 0 : if (synaptics_capability(psmouse))
330 : : return -1;
331 [ # # ]: 0 : if (synaptics_resolution(psmouse))
332 : : return -1;
333 : :
334 : 0 : return 0;
335 : : }
336 : :
337 : 0 : static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
338 : : {
339 : : static unsigned char param = 0xc8;
340 : 0 : struct synaptics_data *priv = psmouse->private;
341 : :
342 [ # # ]: 0 : if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
343 : : SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
344 : : return 0;
345 : :
346 [ # # ]: 0 : if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
347 : : return -1;
348 : :
349 [ # # ]: 0 : if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE))
350 : : return -1;
351 : :
352 : : /* Advanced gesture mode also sends multi finger data */
353 : 0 : priv->capabilities |= BIT(1);
354 : :
355 : 0 : return 0;
356 : : }
357 : :
358 : 0 : static int synaptics_set_mode(struct psmouse *psmouse)
359 : : {
360 : 0 : struct synaptics_data *priv = psmouse->private;
361 : :
362 : 0 : priv->mode = 0;
363 [ # # ]: 0 : if (priv->absolute_mode)
364 : 0 : priv->mode |= SYN_BIT_ABSOLUTE_MODE;
365 [ # # ]: 0 : if (priv->disable_gesture)
366 : 0 : priv->mode |= SYN_BIT_DISABLE_GESTURE;
367 [ # # ]: 0 : if (psmouse->rate >= 80)
368 : 0 : priv->mode |= SYN_BIT_HIGH_RATE;
369 [ # # ]: 0 : if (SYN_CAP_EXTENDED(priv->capabilities))
370 : 0 : priv->mode |= SYN_BIT_W_MODE;
371 : :
372 [ # # ]: 0 : if (synaptics_mode_cmd(psmouse, priv->mode))
373 : : return -1;
374 : :
375 [ # # # # ]: 0 : if (priv->absolute_mode &&
376 : 0 : synaptics_set_advanced_gesture_mode(psmouse)) {
377 : 0 : psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
378 : 0 : return -1;
379 : : }
380 : :
381 : : return 0;
382 : : }
383 : :
384 : 0 : static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
385 : : {
386 : 0 : struct synaptics_data *priv = psmouse->private;
387 : :
388 [ # # ]: 0 : if (rate >= 80) {
389 : 0 : priv->mode |= SYN_BIT_HIGH_RATE;
390 : 0 : psmouse->rate = 80;
391 : : } else {
392 : 0 : priv->mode &= ~SYN_BIT_HIGH_RATE;
393 : 0 : psmouse->rate = 40;
394 : : }
395 : :
396 : 0 : synaptics_mode_cmd(psmouse, priv->mode);
397 : 0 : }
398 : :
399 : : /*****************************************************************************
400 : : * Synaptics pass-through PS/2 port support
401 : : ****************************************************************************/
402 : 0 : static int synaptics_pt_write(struct serio *serio, unsigned char c)
403 : : {
404 : 0 : struct psmouse *parent = serio_get_drvdata(serio->parent);
405 : 0 : char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
406 : :
407 [ # # ]: 0 : if (psmouse_sliced_command(parent, c))
408 : : return -1;
409 [ # # ]: 0 : if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE))
410 : : return -1;
411 : 0 : return 0;
412 : : }
413 : :
414 : 0 : static int synaptics_pt_start(struct serio *serio)
415 : : {
416 : 0 : struct psmouse *parent = serio_get_drvdata(serio->parent);
417 : 0 : struct synaptics_data *priv = parent->private;
418 : :
419 : 0 : serio_pause_rx(parent->ps2dev.serio);
420 : 0 : priv->pt_port = serio;
421 : 0 : serio_continue_rx(parent->ps2dev.serio);
422 : :
423 : 0 : return 0;
424 : : }
425 : :
426 : 0 : static void synaptics_pt_stop(struct serio *serio)
427 : : {
428 : 0 : struct psmouse *parent = serio_get_drvdata(serio->parent);
429 : 0 : struct synaptics_data *priv = parent->private;
430 : :
431 : 0 : serio_pause_rx(parent->ps2dev.serio);
432 : 0 : priv->pt_port = NULL;
433 : 0 : serio_continue_rx(parent->ps2dev.serio);
434 : 0 : }
435 : :
436 : : static int synaptics_is_pt_packet(unsigned char *buf)
437 : : {
438 [ # # ][ # # ]: 0 : return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
439 : : }
440 : :
441 : 0 : static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
442 : : {
443 : : struct psmouse *child = serio_get_drvdata(ptport);
444 : :
445 [ # # ][ # # ]: 0 : if (child && child->state == PSMOUSE_ACTIVATED) {
446 : 0 : serio_interrupt(ptport, packet[1], 0);
447 : 0 : serio_interrupt(ptport, packet[4], 0);
448 : 0 : serio_interrupt(ptport, packet[5], 0);
449 [ # # ]: 0 : if (child->pktsize == 4)
450 : 0 : serio_interrupt(ptport, packet[2], 0);
451 : : } else
452 : 0 : serio_interrupt(ptport, packet[1], 0);
453 : 0 : }
454 : :
455 : 0 : static void synaptics_pt_activate(struct psmouse *psmouse)
456 : : {
457 : 0 : struct synaptics_data *priv = psmouse->private;
458 : 0 : struct psmouse *child = serio_get_drvdata(priv->pt_port);
459 : :
460 : : /* adjust the touchpad to child's choice of protocol */
461 [ # # ]: 0 : if (child) {
462 [ # # ]: 0 : if (child->pktsize == 4)
463 : 0 : priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
464 : : else
465 : 0 : priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
466 : :
467 [ # # ]: 0 : if (synaptics_mode_cmd(psmouse, priv->mode))
468 : 0 : psmouse_warn(psmouse,
469 : : "failed to switch guest protocol\n");
470 : : }
471 : 0 : }
472 : :
473 : 0 : static void synaptics_pt_create(struct psmouse *psmouse)
474 : : {
475 : : struct serio *serio;
476 : :
477 : : serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
478 [ # # ]: 0 : if (!serio) {
479 : 0 : psmouse_err(psmouse,
480 : : "not enough memory for pass-through port\n");
481 : 0 : return;
482 : : }
483 : :
484 : 0 : serio->id.type = SERIO_PS_PSTHRU;
485 : 0 : strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
486 : 0 : strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
487 : 0 : serio->write = synaptics_pt_write;
488 : 0 : serio->start = synaptics_pt_start;
489 : 0 : serio->stop = synaptics_pt_stop;
490 : 0 : serio->parent = psmouse->ps2dev.serio;
491 : :
492 : 0 : psmouse->pt_activate = synaptics_pt_activate;
493 : :
494 : 0 : psmouse_info(psmouse, "serio: %s port at %s\n",
495 : : serio->name, psmouse->phys);
496 : 0 : serio_register_port(serio);
497 : : }
498 : :
499 : : /*****************************************************************************
500 : : * Functions to interpret the absolute mode packets
501 : : ****************************************************************************/
502 : :
503 : : static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count,
504 : : int sgm, int agm)
505 : : {
506 : 0 : state->count = count;
507 : 0 : state->sgm = sgm;
508 : 0 : state->agm = agm;
509 : : }
510 : :
511 : 0 : static void synaptics_parse_agm(const unsigned char buf[],
512 : : struct synaptics_data *priv,
513 : : struct synaptics_hw_state *hw)
514 : : {
515 : : struct synaptics_hw_state *agm = &priv->agm;
516 : : int agm_packet_type;
517 : :
518 : 0 : agm_packet_type = (buf[5] & 0x30) >> 4;
519 [ # # # ]: 0 : switch (agm_packet_type) {
520 : : case 1:
521 : : /* Gesture packet: (x, y, z) half resolution */
522 : 0 : agm->w = hw->w;
523 : 0 : agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1;
524 : 0 : agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1;
525 : 0 : agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1;
526 : : break;
527 : :
528 : : case 2:
529 : : /* AGM-CONTACT packet: (count, sgm, agm) */
530 : 0 : synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]);
531 : : break;
532 : :
533 : : default:
534 : : break;
535 : : }
536 : :
537 : : /* Record that at least one AGM has been received since last SGM */
538 : 0 : priv->agm_pending = true;
539 : 0 : }
540 : :
541 : 0 : static int synaptics_parse_hw_state(const unsigned char buf[],
542 : : struct synaptics_data *priv,
543 : : struct synaptics_hw_state *hw)
544 : : {
545 : 0 : memset(hw, 0, sizeof(struct synaptics_hw_state));
546 : :
547 [ # # ]: 0 : if (SYN_MODEL_NEWABS(priv->model_id)) {
548 : 0 : hw->w = (((buf[0] & 0x30) >> 2) |
549 : 0 : ((buf[0] & 0x04) >> 1) |
550 : 0 : ((buf[3] & 0x04) >> 2));
551 : :
552 : 0 : hw->left = (buf[0] & 0x01) ? 1 : 0;
553 : 0 : hw->right = (buf[0] & 0x02) ? 1 : 0;
554 : :
555 [ # # ]: 0 : if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
556 : : /*
557 : : * Clickpad's button is transmitted as middle button,
558 : : * however, since it is primary button, we will report
559 : : * it as BTN_LEFT.
560 : : */
561 : 0 : hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
562 : :
563 [ # # ]: 0 : } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
564 : 0 : hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
565 [ # # ]: 0 : if (hw->w == 2)
566 : 0 : hw->scroll = (signed char)(buf[1]);
567 : : }
568 : :
569 [ # # ]: 0 : if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
570 : 0 : hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
571 : 0 : hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
572 : : }
573 : :
574 [ # # ]: 0 : if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
575 [ # # ]: 0 : SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
576 : : hw->w == 2) {
577 : 0 : synaptics_parse_agm(buf, priv, hw);
578 : 0 : return 1;
579 : : }
580 : :
581 : 0 : hw->x = (((buf[3] & 0x10) << 8) |
582 : 0 : ((buf[1] & 0x0f) << 8) |
583 : 0 : buf[4]);
584 : 0 : hw->y = (((buf[3] & 0x20) << 7) |
585 : 0 : ((buf[1] & 0xf0) << 4) |
586 : 0 : buf[5]);
587 : 0 : hw->z = buf[2];
588 : :
589 [ # # ][ # # ]: 0 : if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
590 : 0 : ((buf[0] ^ buf[3]) & 0x02)) {
591 [ # # # # : 0 : switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
# ]
592 : : default:
593 : : /*
594 : : * if nExtBtn is greater than 8 it should be
595 : : * considered invalid and treated as 0
596 : : */
597 : : break;
598 : : case 8:
599 [ # # ]: 0 : hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
600 [ # # ]: 0 : hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
601 : : case 6:
602 [ # # ]: 0 : hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
603 [ # # ]: 0 : hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
604 : : case 4:
605 [ # # ]: 0 : hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
606 [ # # ]: 0 : hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
607 : : case 2:
608 [ # # ]: 0 : hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
609 : 0 : hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
610 : : }
611 : : }
612 : : } else {
613 : 0 : hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
614 : 0 : hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);
615 : :
616 : 0 : hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
617 : 0 : hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
618 : :
619 : 0 : hw->left = (buf[0] & 0x01) ? 1 : 0;
620 : 0 : hw->right = (buf[0] & 0x02) ? 1 : 0;
621 : : }
622 : :
623 : : /*
624 : : * Convert wrap-around values to negative. (X|Y)_MAX_POSITIVE
625 : : * is used by some firmware to indicate a finger at the edge of
626 : : * the touchpad whose precise position cannot be determined, so
627 : : * convert these values to the maximum axis value.
628 : : */
629 [ # # ]: 0 : if (hw->x > X_MAX_POSITIVE)
630 : 0 : hw->x -= 1 << ABS_POS_BITS;
631 [ # # ]: 0 : else if (hw->x == X_MAX_POSITIVE)
632 : 0 : hw->x = XMAX;
633 : :
634 [ # # ]: 0 : if (hw->y > Y_MAX_POSITIVE)
635 : 0 : hw->y -= 1 << ABS_POS_BITS;
636 [ # # ]: 0 : else if (hw->y == Y_MAX_POSITIVE)
637 : 0 : hw->y = YMAX;
638 : :
639 : : return 0;
640 : : }
641 : :
642 : 0 : static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot,
643 : : bool active, int x, int y)
644 : : {
645 : : input_mt_slot(dev, slot);
646 : 0 : input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
647 [ # # ]: 0 : if (active) {
648 : : input_report_abs(dev, ABS_MT_POSITION_X, x);
649 : : input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(y));
650 : : }
651 : 0 : }
652 : :
653 : 0 : static void synaptics_report_semi_mt_data(struct input_dev *dev,
654 : : const struct synaptics_hw_state *a,
655 : : const struct synaptics_hw_state *b,
656 : : int num_fingers)
657 : : {
658 [ # # ]: 0 : if (num_fingers >= 2) {
659 : 0 : synaptics_report_semi_mt_slot(dev, 0, true, min(a->x, b->x),
660 : 0 : min(a->y, b->y));
661 : 0 : synaptics_report_semi_mt_slot(dev, 1, true, max(a->x, b->x),
662 : 0 : max(a->y, b->y));
663 [ # # ]: 0 : } else if (num_fingers == 1) {
664 : 0 : synaptics_report_semi_mt_slot(dev, 0, true, a->x, a->y);
665 : 0 : synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
666 : : } else {
667 : 0 : synaptics_report_semi_mt_slot(dev, 0, false, 0, 0);
668 : 0 : synaptics_report_semi_mt_slot(dev, 1, false, 0, 0);
669 : : }
670 : 0 : }
671 : :
672 : 0 : static void synaptics_report_buttons(struct psmouse *psmouse,
673 : : const struct synaptics_hw_state *hw)
674 : : {
675 : 0 : struct input_dev *dev = psmouse->dev;
676 : 0 : struct synaptics_data *priv = psmouse->private;
677 : : int i;
678 : :
679 : 0 : input_report_key(dev, BTN_LEFT, hw->left);
680 : 0 : input_report_key(dev, BTN_RIGHT, hw->right);
681 : :
682 [ # # ]: 0 : if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
683 : 0 : input_report_key(dev, BTN_MIDDLE, hw->middle);
684 : :
685 [ # # ]: 0 : if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
686 : 0 : input_report_key(dev, BTN_FORWARD, hw->up);
687 : 0 : input_report_key(dev, BTN_BACK, hw->down);
688 : : }
689 : :
690 [ # # ]: 0 : for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
691 : 0 : input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
692 : 0 : }
693 : :
694 : 0 : static void synaptics_report_slot(struct input_dev *dev, int slot,
695 : : const struct synaptics_hw_state *hw)
696 : : {
697 : : input_mt_slot(dev, slot);
698 : 0 : input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL));
699 [ # # ]: 0 : if (!hw)
700 : 0 : return;
701 : :
702 : 0 : input_report_abs(dev, ABS_MT_POSITION_X, hw->x);
703 : 0 : input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y));
704 : 0 : input_report_abs(dev, ABS_MT_PRESSURE, hw->z);
705 : : }
706 : :
707 : 0 : static void synaptics_report_mt_data(struct psmouse *psmouse,
708 : : struct synaptics_mt_state *mt_state,
709 : : const struct synaptics_hw_state *sgm)
710 : : {
711 : 0 : struct input_dev *dev = psmouse->dev;
712 : 0 : struct synaptics_data *priv = psmouse->private;
713 : 0 : struct synaptics_hw_state *agm = &priv->agm;
714 : : struct synaptics_mt_state *old = &priv->mt_state;
715 : :
716 [ # # # ]: 0 : switch (mt_state->count) {
717 : : case 0:
718 : 0 : synaptics_report_slot(dev, 0, NULL);
719 : 0 : synaptics_report_slot(dev, 1, NULL);
720 : 0 : break;
721 : : case 1:
722 [ # # ]: 0 : if (mt_state->sgm == -1) {
723 : 0 : synaptics_report_slot(dev, 0, NULL);
724 : 0 : synaptics_report_slot(dev, 1, NULL);
725 [ # # ]: 0 : } else if (mt_state->sgm == 0) {
726 : 0 : synaptics_report_slot(dev, 0, sgm);
727 : 0 : synaptics_report_slot(dev, 1, NULL);
728 : : } else {
729 : 0 : synaptics_report_slot(dev, 0, NULL);
730 : 0 : synaptics_report_slot(dev, 1, sgm);
731 : : }
732 : : break;
733 : : default:
734 : : /*
735 : : * If the finger slot contained in SGM is valid, and either
736 : : * hasn't changed, or is new, or the old SGM has now moved to
737 : : * AGM, then report SGM in MTB slot 0.
738 : : * Otherwise, empty MTB slot 0.
739 : : */
740 [ # # ][ # # ]: 0 : if (mt_state->sgm != -1 &&
741 [ # # ]: 0 : (mt_state->sgm == old->sgm ||
742 [ # # ]: 0 : old->sgm == -1 || mt_state->agm == old->sgm))
743 : 0 : synaptics_report_slot(dev, 0, sgm);
744 : : else
745 : 0 : synaptics_report_slot(dev, 0, NULL);
746 : :
747 : : /*
748 : : * If the finger slot contained in AGM is valid, and either
749 : : * hasn't changed, or is new, then report AGM in MTB slot 1.
750 : : * Otherwise, empty MTB slot 1.
751 : : *
752 : : * However, in the case where the AGM is new, make sure that
753 : : * that it is either the same as the old SGM, or there was no
754 : : * SGM.
755 : : *
756 : : * Otherwise, if the SGM was just 1, and the new AGM is 2, then
757 : : * the new AGM will keep the old SGM's tracking ID, which can
758 : : * cause apparent drumroll. This happens if in the following
759 : : * valid finger sequence:
760 : : *
761 : : * Action SGM AGM (MTB slot:Contact)
762 : : * 1. Touch contact 0 (0:0)
763 : : * 2. Touch contact 1 (0:0, 1:1)
764 : : * 3. Lift contact 0 (1:1)
765 : : * 4. Touch contacts 2,3 (0:2, 1:3)
766 : : *
767 : : * In step 4, contact 3, in AGM must not be given the same
768 : : * tracking ID as contact 1 had in step 3. To avoid this,
769 : : * the first agm with contact 3 is dropped and slot 1 is
770 : : * invalidated (tracking ID = -1).
771 : : */
772 [ # # ][ # # ]: 0 : if (mt_state->agm != -1 &&
773 [ # # ]: 0 : (mt_state->agm == old->agm ||
774 [ # # ]: 0 : (old->agm == -1 &&
775 [ # # ]: 0 : (old->sgm == -1 || mt_state->agm == old->sgm))))
776 : 0 : synaptics_report_slot(dev, 1, agm);
777 : : else
778 : 0 : synaptics_report_slot(dev, 1, NULL);
779 : : break;
780 : : }
781 : :
782 : : /* Don't use active slot count to generate BTN_TOOL events. */
783 : 0 : input_mt_report_pointer_emulation(dev, false);
784 : :
785 : : /* Send the number of fingers reported by touchpad itself. */
786 : 0 : input_mt_report_finger_count(dev, mt_state->count);
787 : :
788 : 0 : synaptics_report_buttons(psmouse, sgm);
789 : :
790 : : input_sync(dev);
791 : 0 : }
792 : :
793 : : /* Handle case where mt_state->count = 0 */
794 : : static void synaptics_image_sensor_0f(struct synaptics_data *priv,
795 : : struct synaptics_mt_state *mt_state)
796 : : {
797 : : synaptics_mt_state_set(mt_state, 0, -1, -1);
798 : 0 : priv->mt_state_lost = false;
799 : : }
800 : :
801 : : /* Handle case where mt_state->count = 1 */
802 : 0 : static void synaptics_image_sensor_1f(struct synaptics_data *priv,
803 : : struct synaptics_mt_state *mt_state)
804 : : {
805 : : struct synaptics_hw_state *agm = &priv->agm;
806 : : struct synaptics_mt_state *old = &priv->mt_state;
807 : :
808 : : /*
809 : : * If the last AGM was (0,0,0), and there is only one finger left,
810 : : * then we absolutely know that SGM contains slot 0, and all other
811 : : * fingers have been removed.
812 : : */
813 [ # # ][ # # ]: 0 : if (priv->agm_pending && agm->z == 0) {
814 : : synaptics_mt_state_set(mt_state, 1, 0, -1);
815 : 0 : priv->mt_state_lost = false;
816 : 0 : return;
817 : : }
818 : :
819 [ # # # # : 0 : switch (old->count) {
# ]
820 : : case 0:
821 : : synaptics_mt_state_set(mt_state, 1, 0, -1);
822 : : break;
823 : : case 1:
824 : : /*
825 : : * If mt_state_lost, then the previous transition was 3->1,
826 : : * and SGM now contains either slot 0 or 1, but we don't know
827 : : * which. So, we just assume that the SGM now contains slot 1.
828 : : *
829 : : * If pending AGM and either:
830 : : * (a) the previous SGM slot contains slot 0, or
831 : : * (b) there was no SGM slot
832 : : * then, the SGM now contains slot 1
833 : : *
834 : : * Case (a) happens with very rapid "drum roll" gestures, where
835 : : * slot 0 finger is lifted and a new slot 1 finger touches
836 : : * within one reporting interval.
837 : : *
838 : : * Case (b) happens if initially two or more fingers tap
839 : : * briefly, and all but one lift before the end of the first
840 : : * reporting interval.
841 : : *
842 : : * (In both these cases, slot 0 will becomes empty, so SGM
843 : : * contains slot 1 with the new finger)
844 : : *
845 : : * Else, if there was no previous SGM, it now contains slot 0.
846 : : *
847 : : * Otherwise, SGM still contains the same slot.
848 : : */
849 [ # # ][ # # ]: 0 : if (priv->mt_state_lost ||
850 [ # # ]: 0 : (priv->agm_pending && old->sgm <= 0))
851 : : synaptics_mt_state_set(mt_state, 1, 1, -1);
852 [ # # ]: 0 : else if (old->sgm == -1)
853 : : synaptics_mt_state_set(mt_state, 1, 0, -1);
854 : : break;
855 : : case 2:
856 : : /*
857 : : * If mt_state_lost, we don't know which finger SGM contains.
858 : : *
859 : : * So, report 1 finger, but with both slots empty.
860 : : * We will use slot 1 on subsequent 1->1
861 : : */
862 [ # # ]: 0 : if (priv->mt_state_lost) {
863 : : synaptics_mt_state_set(mt_state, 1, -1, -1);
864 : : break;
865 : : }
866 : : /*
867 : : * Since the last AGM was NOT (0,0,0), it was the finger in
868 : : * slot 0 that has been removed.
869 : : * So, SGM now contains previous AGM's slot, and AGM is now
870 : : * empty.
871 : : */
872 : 0 : synaptics_mt_state_set(mt_state, 1, old->agm, -1);
873 : : break;
874 : : case 3:
875 : : /*
876 : : * Since last AGM was not (0,0,0), we don't know which finger
877 : : * is left.
878 : : *
879 : : * So, report 1 finger, but with both slots empty.
880 : : * We will use slot 1 on subsequent 1->1
881 : : */
882 : : synaptics_mt_state_set(mt_state, 1, -1, -1);
883 : 0 : priv->mt_state_lost = true;
884 : 0 : break;
885 : : case 4:
886 : : case 5:
887 : : /* mt_state was updated by AGM-CONTACT packet */
888 : : break;
889 : : }
890 : : }
891 : :
892 : : /* Handle case where mt_state->count = 2 */
893 : 0 : static void synaptics_image_sensor_2f(struct synaptics_data *priv,
894 : : struct synaptics_mt_state *mt_state)
895 : : {
896 : : struct synaptics_mt_state *old = &priv->mt_state;
897 : :
898 [ # # # # : 0 : switch (old->count) {
# ]
899 : : case 0:
900 : : synaptics_mt_state_set(mt_state, 2, 0, 1);
901 : : break;
902 : : case 1:
903 : : /*
904 : : * If previous SGM contained slot 1 or higher, SGM now contains
905 : : * slot 0 (the newly touching finger) and AGM contains SGM's
906 : : * previous slot.
907 : : *
908 : : * Otherwise, SGM still contains slot 0 and AGM now contains
909 : : * slot 1.
910 : : */
911 [ # # ]: 0 : if (old->sgm >= 1)
912 : : synaptics_mt_state_set(mt_state, 2, 0, old->sgm);
913 : : else
914 : : synaptics_mt_state_set(mt_state, 2, 0, 1);
915 : : break;
916 : : case 2:
917 : : /*
918 : : * If mt_state_lost, SGM now contains either finger 1 or 2, but
919 : : * we don't know which.
920 : : * So, we just assume that the SGM contains slot 0 and AGM 1.
921 : : */
922 [ # # ]: 0 : if (priv->mt_state_lost)
923 : : synaptics_mt_state_set(mt_state, 2, 0, 1);
924 : : /*
925 : : * Otherwise, use the same mt_state, since it either hasn't
926 : : * changed, or was updated by a recently received AGM-CONTACT
927 : : * packet.
928 : : */
929 : : break;
930 : : case 3:
931 : : /*
932 : : * 3->2 transitions have two unsolvable problems:
933 : : * 1) no indication is given which finger was removed
934 : : * 2) no way to tell if agm packet was for finger 3
935 : : * before 3->2, or finger 2 after 3->2.
936 : : *
937 : : * So, report 2 fingers, but empty all slots.
938 : : * We will guess slots [0,1] on subsequent 2->2.
939 : : */
940 : : synaptics_mt_state_set(mt_state, 2, -1, -1);
941 : 0 : priv->mt_state_lost = true;
942 : 0 : break;
943 : : case 4:
944 : : case 5:
945 : : /* mt_state was updated by AGM-CONTACT packet */
946 : : break;
947 : : }
948 : 0 : }
949 : :
950 : : /* Handle case where mt_state->count = 3 */
951 : 0 : static void synaptics_image_sensor_3f(struct synaptics_data *priv,
952 : : struct synaptics_mt_state *mt_state)
953 : : {
954 : : struct synaptics_mt_state *old = &priv->mt_state;
955 : :
956 [ # # # # : 0 : switch (old->count) {
# ]
957 : : case 0:
958 : : synaptics_mt_state_set(mt_state, 3, 0, 2);
959 : : break;
960 : : case 1:
961 : : /*
962 : : * If previous SGM contained slot 2 or higher, SGM now contains
963 : : * slot 0 (one of the newly touching fingers) and AGM contains
964 : : * SGM's previous slot.
965 : : *
966 : : * Otherwise, SGM now contains slot 0 and AGM contains slot 2.
967 : : */
968 [ # # ]: 0 : if (old->sgm >= 2)
969 : : synaptics_mt_state_set(mt_state, 3, 0, old->sgm);
970 : : else
971 : : synaptics_mt_state_set(mt_state, 3, 0, 2);
972 : : break;
973 : : case 2:
974 : : /*
975 : : * If the AGM previously contained slot 3 or higher, then the
976 : : * newly touching finger is in the lowest available slot.
977 : : *
978 : : * If SGM was previously 1 or higher, then the new SGM is
979 : : * now slot 0 (with a new finger), otherwise, the new finger
980 : : * is now in a hidden slot between 0 and AGM's slot.
981 : : *
982 : : * In all such cases, the SGM now contains slot 0, and the AGM
983 : : * continues to contain the same slot as before.
984 : : */
985 [ # # ]: 0 : if (old->agm >= 3) {
986 : : synaptics_mt_state_set(mt_state, 3, 0, old->agm);
987 : : break;
988 : : }
989 : :
990 : : /*
991 : : * After some 3->1 and all 3->2 transitions, we lose track
992 : : * of which slot is reported by SGM and AGM.
993 : : *
994 : : * For 2->3 in this state, report 3 fingers, but empty all
995 : : * slots, and we will guess (0,2) on a subsequent 0->3.
996 : : *
997 : : * To userspace, the resulting transition will look like:
998 : : * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2]
999 : : */
1000 [ # # ]: 0 : if (priv->mt_state_lost) {
1001 : : synaptics_mt_state_set(mt_state, 3, -1, -1);
1002 : : break;
1003 : : }
1004 : :
1005 : : /*
1006 : : * If the (SGM,AGM) really previously contained slots (0, 1),
1007 : : * then we cannot know what slot was just reported by the AGM,
1008 : : * because the 2->3 transition can occur either before or after
1009 : : * the AGM packet. Thus, this most recent AGM could contain
1010 : : * either the same old slot 1 or the new slot 2.
1011 : : * Subsequent AGMs will be reporting slot 2.
1012 : : *
1013 : : * To userspace, the resulting transition will look like:
1014 : : * 2:[0,1] -> 3:[0,-1] -> 3:[0,2]
1015 : : */
1016 : : synaptics_mt_state_set(mt_state, 3, 0, -1);
1017 : : break;
1018 : : case 3:
1019 : : /*
1020 : : * If, for whatever reason, the previous agm was invalid,
1021 : : * Assume SGM now contains slot 0, AGM now contains slot 2.
1022 : : */
1023 [ # # ]: 0 : if (old->agm <= 2)
1024 : : synaptics_mt_state_set(mt_state, 3, 0, 2);
1025 : : /*
1026 : : * mt_state either hasn't changed, or was updated by a recently
1027 : : * received AGM-CONTACT packet.
1028 : : */
1029 : : break;
1030 : :
1031 : : case 4:
1032 : : case 5:
1033 : : /* mt_state was updated by AGM-CONTACT packet */
1034 : : break;
1035 : : }
1036 : 0 : }
1037 : :
1038 : : /* Handle case where mt_state->count = 4, or = 5 */
1039 : : static void synaptics_image_sensor_45f(struct synaptics_data *priv,
1040 : : struct synaptics_mt_state *mt_state)
1041 : : {
1042 : : /* mt_state was updated correctly by AGM-CONTACT packet */
1043 : 0 : priv->mt_state_lost = false;
1044 : : }
1045 : :
1046 : 0 : static void synaptics_image_sensor_process(struct psmouse *psmouse,
1047 : : struct synaptics_hw_state *sgm)
1048 : : {
1049 : 0 : struct synaptics_data *priv = psmouse->private;
1050 : : struct synaptics_hw_state *agm = &priv->agm;
1051 : : struct synaptics_mt_state mt_state;
1052 : :
1053 : : /* Initialize using current mt_state (as updated by last agm) */
1054 : 0 : mt_state = agm->mt_state;
1055 : :
1056 : : /*
1057 : : * Update mt_state using the new finger count and current mt_state.
1058 : : */
1059 [ # # ]: 0 : if (sgm->z == 0)
1060 : : synaptics_image_sensor_0f(priv, &mt_state);
1061 [ # # ]: 0 : else if (sgm->w >= 4)
1062 : 0 : synaptics_image_sensor_1f(priv, &mt_state);
1063 [ # # ]: 0 : else if (sgm->w == 0)
1064 : 0 : synaptics_image_sensor_2f(priv, &mt_state);
1065 [ # # ][ # # ]: 0 : else if (sgm->w == 1 && mt_state.count <= 3)
1066 : 0 : synaptics_image_sensor_3f(priv, &mt_state);
1067 : : else
1068 : : synaptics_image_sensor_45f(priv, &mt_state);
1069 : :
1070 : : /* Send resulting input events to user space */
1071 : 0 : synaptics_report_mt_data(psmouse, &mt_state, sgm);
1072 : :
1073 : : /* Store updated mt_state */
1074 : 0 : priv->mt_state = agm->mt_state = mt_state;
1075 : 0 : priv->agm_pending = false;
1076 : 0 : }
1077 : :
1078 : : /*
1079 : : * called for each full received packet from the touchpad
1080 : : */
1081 : 0 : static void synaptics_process_packet(struct psmouse *psmouse)
1082 : : {
1083 : 0 : struct input_dev *dev = psmouse->dev;
1084 : 0 : struct synaptics_data *priv = psmouse->private;
1085 : : struct synaptics_hw_state hw;
1086 : : int num_fingers;
1087 : : int finger_width;
1088 : :
1089 [ # # ]: 0 : if (synaptics_parse_hw_state(psmouse->packet, priv, &hw))
1090 : 0 : return;
1091 : :
1092 [ # # ]: 0 : if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
1093 : 0 : synaptics_image_sensor_process(psmouse, &hw);
1094 : 0 : return;
1095 : : }
1096 : :
1097 [ # # ]: 0 : if (hw.scroll) {
1098 : 0 : priv->scroll += hw.scroll;
1099 : :
1100 [ # # ]: 0 : while (priv->scroll >= 4) {
1101 : 0 : input_report_key(dev, BTN_BACK, !hw.down);
1102 : : input_sync(dev);
1103 : 0 : input_report_key(dev, BTN_BACK, hw.down);
1104 : : input_sync(dev);
1105 : 0 : priv->scroll -= 4;
1106 : : }
1107 [ # # ]: 0 : while (priv->scroll <= -4) {
1108 : 0 : input_report_key(dev, BTN_FORWARD, !hw.up);
1109 : : input_sync(dev);
1110 : 0 : input_report_key(dev, BTN_FORWARD, hw.up);
1111 : : input_sync(dev);
1112 : 0 : priv->scroll += 4;
1113 : : }
1114 : : return;
1115 : : }
1116 : :
1117 [ # # ][ # # ]: 0 : if (hw.z > 0 && hw.x > 1) {
1118 : : num_fingers = 1;
1119 : : finger_width = 5;
1120 [ # # ]: 0 : if (SYN_CAP_EXTENDED(priv->capabilities)) {
1121 [ # # # ]: 0 : switch (hw.w) {
1122 : : case 0 ... 1:
1123 [ # # ]: 0 : if (SYN_CAP_MULTIFINGER(priv->capabilities))
1124 : 0 : num_fingers = hw.w + 2;
1125 : : break;
1126 : : case 2:
1127 : : if (SYN_MODEL_PEN(priv->model_id))
1128 : : ; /* Nothing, treat a pen as a single finger */
1129 : : break;
1130 : : case 4 ... 15:
1131 [ # # ]: 0 : if (SYN_CAP_PALMDETECT(priv->capabilities))
1132 : : finger_width = hw.w;
1133 : : break;
1134 : : }
1135 : : }
1136 : : } else {
1137 : : num_fingers = 0;
1138 : : finger_width = 0;
1139 : : }
1140 : :
1141 [ # # ]: 0 : if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
1142 : 0 : synaptics_report_semi_mt_data(dev, &hw, &priv->agm,
1143 : : num_fingers);
1144 : :
1145 : : /* Post events
1146 : : * BTN_TOUCH has to be first as mousedev relies on it when doing
1147 : : * absolute -> relative conversion
1148 : : */
1149 [ # # ]: 0 : if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
1150 [ # # ]: 0 : if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
1151 : :
1152 [ # # ]: 0 : if (num_fingers > 0) {
1153 : 0 : input_report_abs(dev, ABS_X, hw.x);
1154 : 0 : input_report_abs(dev, ABS_Y, synaptics_invert_y(hw.y));
1155 : : }
1156 : 0 : input_report_abs(dev, ABS_PRESSURE, hw.z);
1157 : :
1158 [ # # ]: 0 : if (SYN_CAP_PALMDETECT(priv->capabilities))
1159 : : input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
1160 : :
1161 : 0 : input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
1162 [ # # ]: 0 : if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
1163 : 0 : input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
1164 : 0 : input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
1165 : : }
1166 : :
1167 : 0 : synaptics_report_buttons(psmouse, &hw);
1168 : :
1169 : : input_sync(dev);
1170 : : }
1171 : :
1172 : 0 : static int synaptics_validate_byte(struct psmouse *psmouse,
1173 : : int idx, unsigned char pkt_type)
1174 : : {
1175 : : static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
1176 : : static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
1177 : : static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
1178 : : static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
1179 : : static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
1180 : 0 : const char *packet = psmouse->packet;
1181 : :
1182 [ # # ]: 0 : if (idx < 0 || idx > 4)
1183 : : return 0;
1184 : :
1185 [ # # # # ]: 0 : switch (pkt_type) {
1186 : :
1187 : : case SYN_NEWABS:
1188 : : case SYN_NEWABS_RELAXED:
1189 : 0 : return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
1190 : :
1191 : : case SYN_NEWABS_STRICT:
1192 : 0 : return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
1193 : :
1194 : : case SYN_OLDABS:
1195 : 0 : return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
1196 : :
1197 : : default:
1198 : 0 : psmouse_err(psmouse, "unknown packet type %d\n", pkt_type);
1199 : 0 : return 0;
1200 : : }
1201 : : }
1202 : :
1203 : 0 : static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
1204 : : {
1205 : : int i;
1206 : :
1207 [ # # ]: 0 : for (i = 0; i < 5; i++)
1208 [ # # ]: 0 : if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) {
1209 : 0 : psmouse_info(psmouse, "using relaxed packet validation\n");
1210 : 0 : return SYN_NEWABS_RELAXED;
1211 : : }
1212 : :
1213 : : return SYN_NEWABS_STRICT;
1214 : : }
1215 : :
1216 : 0 : static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
1217 : : {
1218 : 0 : struct synaptics_data *priv = psmouse->private;
1219 : :
1220 [ # # ]: 0 : if (psmouse->pktcnt >= 6) { /* Full packet received */
1221 [ # # ]: 0 : if (unlikely(priv->pkt_type == SYN_NEWABS))
1222 : 0 : priv->pkt_type = synaptics_detect_pkt_type(psmouse);
1223 : :
1224 [ # # ][ # # ]: 0 : if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
1225 : : synaptics_is_pt_packet(psmouse->packet)) {
1226 [ # # ]: 0 : if (priv->pt_port)
1227 : 0 : synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
1228 : : } else
1229 : 0 : synaptics_process_packet(psmouse);
1230 : :
1231 : : return PSMOUSE_FULL_PACKET;
1232 : : }
1233 : :
1234 : 0 : return synaptics_validate_byte(psmouse, psmouse->pktcnt - 1, priv->pkt_type) ?
1235 : 0 : PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
1236 : : }
1237 : :
1238 : : /*****************************************************************************
1239 : : * Driver initialization/cleanup functions
1240 : : ****************************************************************************/
1241 : 0 : static void set_abs_position_params(struct input_dev *dev,
1242 : : struct synaptics_data *priv, int x_code,
1243 : : int y_code)
1244 : : {
1245 [ # # ]: 0 : int x_min = priv->x_min ?: XMIN_NOMINAL;
1246 [ # # ]: 0 : int x_max = priv->x_max ?: XMAX_NOMINAL;
1247 [ # # ]: 0 : int y_min = priv->y_min ?: YMIN_NOMINAL;
1248 [ # # ]: 0 : int y_max = priv->y_max ?: YMAX_NOMINAL;
1249 : 0 : int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ?
1250 [ # # ]: 0 : SYN_REDUCED_FILTER_FUZZ : 0;
1251 : :
1252 : 0 : input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0);
1253 : 0 : input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0);
1254 : 0 : input_abs_set_res(dev, x_code, priv->x_res);
1255 : 0 : input_abs_set_res(dev, y_code, priv->y_res);
1256 : 0 : }
1257 : :
1258 : 0 : static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
1259 : : {
1260 : : int i;
1261 : :
1262 : : /* Things that apply to both modes */
1263 : : __set_bit(INPUT_PROP_POINTER, dev->propbit);
1264 : : __set_bit(EV_KEY, dev->evbit);
1265 : : __set_bit(BTN_LEFT, dev->keybit);
1266 : : __set_bit(BTN_RIGHT, dev->keybit);
1267 : :
1268 [ # # ]: 0 : if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
1269 : : __set_bit(BTN_MIDDLE, dev->keybit);
1270 : :
1271 [ # # ]: 0 : if (!priv->absolute_mode) {
1272 : : /* Relative mode */
1273 : : __set_bit(EV_REL, dev->evbit);
1274 : : __set_bit(REL_X, dev->relbit);
1275 : : __set_bit(REL_Y, dev->relbit);
1276 : 0 : return;
1277 : : }
1278 : :
1279 : : /* Absolute mode */
1280 : : __set_bit(EV_ABS, dev->evbit);
1281 : 0 : set_abs_position_params(dev, priv, ABS_X, ABS_Y);
1282 : 0 : input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
1283 : :
1284 [ # # ]: 0 : if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
1285 : 0 : set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
1286 : : ABS_MT_POSITION_Y);
1287 : : /* Image sensors can report per-contact pressure */
1288 : 0 : input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
1289 : 0 : input_mt_init_slots(dev, 2, INPUT_MT_POINTER);
1290 : :
1291 : : /* Image sensors can signal 4 and 5 finger clicks */
1292 : : __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
1293 : : __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
1294 [ # # ]: 0 : } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
1295 : : /* Non-image sensors with AGM use semi-mt */
1296 : : __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
1297 : 0 : input_mt_init_slots(dev, 2, 0);
1298 : 0 : set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
1299 : : ABS_MT_POSITION_Y);
1300 : : }
1301 : :
1302 [ # # ]: 0 : if (SYN_CAP_PALMDETECT(priv->capabilities))
1303 : 0 : input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
1304 : :
1305 : : __set_bit(BTN_TOUCH, dev->keybit);
1306 : : __set_bit(BTN_TOOL_FINGER, dev->keybit);
1307 : :
1308 [ # # ]: 0 : if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
1309 : : __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
1310 : : __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
1311 : : }
1312 : :
1313 [ # # ]: 0 : if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
1314 : : SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
1315 : : __set_bit(BTN_FORWARD, dev->keybit);
1316 : : __set_bit(BTN_BACK, dev->keybit);
1317 : : }
1318 : :
1319 [ # # ]: 0 : for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
1320 : 0 : __set_bit(BTN_0 + i, dev->keybit);
1321 : :
1322 : : __clear_bit(EV_REL, dev->evbit);
1323 : : __clear_bit(REL_X, dev->relbit);
1324 : : __clear_bit(REL_Y, dev->relbit);
1325 : :
1326 [ # # ]: 0 : if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
1327 : : __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
1328 : : /* Clickpads report only left button */
1329 : : __clear_bit(BTN_RIGHT, dev->keybit);
1330 : : __clear_bit(BTN_MIDDLE, dev->keybit);
1331 : : }
1332 : : }
1333 : :
1334 : 0 : static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
1335 : : void *data, char *buf)
1336 : : {
1337 : 0 : struct synaptics_data *priv = psmouse->private;
1338 : :
1339 [ # # ]: 0 : return sprintf(buf, "%c\n", priv->disable_gesture ? '1' : '0');
1340 : : }
1341 : :
1342 : 0 : static ssize_t synaptics_set_disable_gesture(struct psmouse *psmouse,
1343 : : void *data, const char *buf,
1344 : : size_t len)
1345 : : {
1346 : 0 : struct synaptics_data *priv = psmouse->private;
1347 : : unsigned int value;
1348 : : int err;
1349 : :
1350 : 0 : err = kstrtouint(buf, 10, &value);
1351 [ # # ]: 0 : if (err)
1352 : : return err;
1353 : :
1354 [ # # ]: 0 : if (value > 1)
1355 : : return -EINVAL;
1356 : :
1357 [ # # ]: 0 : if (value == priv->disable_gesture)
1358 : 0 : return len;
1359 : :
1360 : 0 : priv->disable_gesture = value;
1361 [ # # ]: 0 : if (value)
1362 : 0 : priv->mode |= SYN_BIT_DISABLE_GESTURE;
1363 : : else
1364 : 0 : priv->mode &= ~SYN_BIT_DISABLE_GESTURE;
1365 : :
1366 [ # # ]: 0 : if (synaptics_mode_cmd(psmouse, priv->mode))
1367 : : return -EIO;
1368 : :
1369 : 0 : return len;
1370 : : }
1371 : :
1372 : : PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL,
1373 : : synaptics_show_disable_gesture,
1374 : : synaptics_set_disable_gesture);
1375 : :
1376 : 0 : static void synaptics_disconnect(struct psmouse *psmouse)
1377 : : {
1378 : 0 : struct synaptics_data *priv = psmouse->private;
1379 : :
1380 [ # # ][ # # ]: 0 : if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity))
1381 : 0 : device_remove_file(&psmouse->ps2dev.serio->dev,
1382 : : &psmouse_attr_disable_gesture.dattr);
1383 : :
1384 : : synaptics_reset(psmouse);
1385 : 0 : kfree(priv);
1386 : 0 : psmouse->private = NULL;
1387 : 0 : }
1388 : :
1389 : 0 : static int synaptics_reconnect(struct psmouse *psmouse)
1390 : : {
1391 : 0 : struct synaptics_data *priv = psmouse->private;
1392 : 0 : struct synaptics_data old_priv = *priv;
1393 : : unsigned char param[2];
1394 : : int retry = 0;
1395 : : int error;
1396 : :
1397 : : do {
1398 : 0 : psmouse_reset(psmouse);
1399 [ # # ]: 0 : if (retry) {
1400 : : /*
1401 : : * On some boxes, right after resuming, the touchpad
1402 : : * needs some time to finish initializing (I assume
1403 : : * it needs time to calibrate) and start responding
1404 : : * to Synaptics-specific queries, so let's wait a
1405 : : * bit.
1406 : : */
1407 : : ssleep(1);
1408 : : }
1409 : 0 : ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID);
1410 : 0 : error = synaptics_detect(psmouse, 0);
1411 [ # # ][ # # ]: 0 : } while (error && ++retry < 3);
1412 : :
1413 [ # # ]: 0 : if (error)
1414 : : return -1;
1415 : :
1416 : : if (retry > 1)
1417 : : psmouse_dbg(psmouse, "reconnected after %d tries\n", retry);
1418 : :
1419 [ # # ]: 0 : if (synaptics_query_hardware(psmouse)) {
1420 : 0 : psmouse_err(psmouse, "Unable to query device.\n");
1421 : 0 : return -1;
1422 : : }
1423 : :
1424 [ # # ]: 0 : if (synaptics_set_mode(psmouse)) {
1425 : 0 : psmouse_err(psmouse, "Unable to initialize device.\n");
1426 : 0 : return -1;
1427 : : }
1428 : :
1429 [ # # ][ # # ]: 0 : if (old_priv.identity != priv->identity ||
1430 [ # # ]: 0 : old_priv.model_id != priv->model_id ||
1431 [ # # ]: 0 : old_priv.capabilities != priv->capabilities ||
1432 : 0 : old_priv.ext_cap != priv->ext_cap) {
1433 : 0 : psmouse_err(psmouse,
1434 : : "hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n",
1435 : : old_priv.identity, priv->identity,
1436 : : old_priv.model_id, priv->model_id,
1437 : : old_priv.capabilities, priv->capabilities,
1438 : : old_priv.ext_cap, priv->ext_cap);
1439 : 0 : return -1;
1440 : : }
1441 : :
1442 : : return 0;
1443 : : }
1444 : :
1445 : : static bool impaired_toshiba_kbc;
1446 : :
1447 : : static const struct dmi_system_id toshiba_dmi_table[] __initconst = {
1448 : : #if defined(CONFIG_DMI) && defined(CONFIG_X86)
1449 : : {
1450 : : /* Toshiba Satellite */
1451 : : .matches = {
1452 : : DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1453 : : DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"),
1454 : : },
1455 : : },
1456 : : {
1457 : : /* Toshiba Dynabook */
1458 : : .matches = {
1459 : : DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1460 : : DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"),
1461 : : },
1462 : : },
1463 : : {
1464 : : /* Toshiba Portege M300 */
1465 : : .matches = {
1466 : : DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1467 : : DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"),
1468 : : },
1469 : :
1470 : : },
1471 : : {
1472 : : /* Toshiba Portege M300 */
1473 : : .matches = {
1474 : : DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
1475 : : DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"),
1476 : : DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"),
1477 : : },
1478 : :
1479 : : },
1480 : : #endif
1481 : : { }
1482 : : };
1483 : :
1484 : : static bool broken_olpc_ec;
1485 : :
1486 : : static const struct dmi_system_id olpc_dmi_table[] __initconst = {
1487 : : #if defined(CONFIG_DMI) && defined(CONFIG_OLPC)
1488 : : {
1489 : : /* OLPC XO-1 or XO-1.5 */
1490 : : .matches = {
1491 : : DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
1492 : : DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
1493 : : },
1494 : : },
1495 : : #endif
1496 : : { }
1497 : : };
1498 : :
1499 : : static const struct dmi_system_id min_max_dmi_table[] __initconst = {
1500 : : #if defined(CONFIG_DMI)
1501 : : {
1502 : : /* Lenovo ThinkPad Helix */
1503 : : .matches = {
1504 : : DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1505 : : DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"),
1506 : : },
1507 : : .driver_data = (int []){1024, 5052, 2258, 4832},
1508 : : },
1509 : : {
1510 : : /* Lenovo ThinkPad X240 */
1511 : : .matches = {
1512 : : DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1513 : : DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"),
1514 : : },
1515 : : .driver_data = (int []){1232, 5710, 1156, 4696},
1516 : : },
1517 : : {
1518 : : /* Lenovo ThinkPad T440s */
1519 : : .matches = {
1520 : : DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1521 : : DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"),
1522 : : },
1523 : : .driver_data = (int []){1024, 5112, 2024, 4832},
1524 : : },
1525 : : {
1526 : : /* Lenovo ThinkPad T540p */
1527 : : .matches = {
1528 : : DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1529 : : DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"),
1530 : : },
1531 : : .driver_data = (int []){1024, 5056, 2058, 4832},
1532 : : },
1533 : : #endif
1534 : : { }
1535 : : };
1536 : :
1537 : 0 : void __init synaptics_module_init(void)
1538 : : {
1539 : : const struct dmi_system_id *min_max_dmi;
1540 : :
1541 : 0 : impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
1542 : 0 : broken_olpc_ec = dmi_check_system(olpc_dmi_table);
1543 : :
1544 : : min_max_dmi = dmi_first_match(min_max_dmi_table);
1545 : : if (min_max_dmi)
1546 : : quirk_min_max = min_max_dmi->driver_data;
1547 : 0 : }
1548 : :
1549 : 0 : static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
1550 : : {
1551 : : struct synaptics_data *priv;
1552 : : int err = -1;
1553 : :
1554 : : /*
1555 : : * The OLPC XO has issues with Synaptics' absolute mode; the constant
1556 : : * packet spew overloads the EC such that key presses on the keyboard
1557 : : * are missed. Given that, don't even attempt to use Absolute mode.
1558 : : * Relative mode seems to work just fine.
1559 : : */
1560 [ # # ][ # # ]: 0 : if (absolute_mode && broken_olpc_ec) {
1561 : 0 : psmouse_info(psmouse,
1562 : : "OLPC XO detected, not enabling Synaptics protocol.\n");
1563 : 0 : return -ENODEV;
1564 : : }
1565 : :
1566 : 0 : psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
1567 [ # # ]: 0 : if (!priv)
1568 : : return -ENOMEM;
1569 : :
1570 : 0 : psmouse_reset(psmouse);
1571 : :
1572 [ # # ]: 0 : if (synaptics_query_hardware(psmouse)) {
1573 : 0 : psmouse_err(psmouse, "Unable to query device.\n");
1574 : 0 : goto init_fail;
1575 : : }
1576 : :
1577 : 0 : priv->absolute_mode = absolute_mode;
1578 [ # # ]: 0 : if (SYN_ID_DISGEST_SUPPORTED(priv->identity))
1579 : 0 : priv->disable_gesture = true;
1580 : :
1581 [ # # ]: 0 : if (synaptics_set_mode(psmouse)) {
1582 : 0 : psmouse_err(psmouse, "Unable to initialize device.\n");
1583 : 0 : goto init_fail;
1584 : : }
1585 : :
1586 [ # # ]: 0 : priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
1587 : :
1588 : 0 : psmouse_info(psmouse,
1589 : : "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
1590 : : SYN_ID_MODEL(priv->identity),
1591 : : SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
1592 : : priv->model_id,
1593 : : priv->capabilities, priv->ext_cap, priv->ext_cap_0c,
1594 : : priv->board_id, priv->firmware_id);
1595 : :
1596 : 0 : set_input_params(psmouse->dev, priv);
1597 : :
1598 : : /*
1599 : : * Encode touchpad model so that it can be used to set
1600 : : * input device->id.version and be visible to userspace.
1601 : : * Because version is __u16 we have to drop something.
1602 : : * Hardware info bits seem to be good candidates as they
1603 : : * are documented to be for Synaptics corp. internal use.
1604 : : */
1605 : 0 : psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
1606 : 0 : (priv->model_id & 0x000000ff);
1607 : :
1608 [ # # ]: 0 : if (absolute_mode) {
1609 : 0 : psmouse->protocol_handler = synaptics_process_byte;
1610 : 0 : psmouse->pktsize = 6;
1611 : : } else {
1612 : : /* Relative mode follows standard PS/2 mouse protocol */
1613 : 0 : psmouse->protocol_handler = psmouse_process_byte;
1614 : 0 : psmouse->pktsize = 3;
1615 : : }
1616 : :
1617 : 0 : psmouse->set_rate = synaptics_set_rate;
1618 : 0 : psmouse->disconnect = synaptics_disconnect;
1619 : 0 : psmouse->reconnect = synaptics_reconnect;
1620 : 0 : psmouse->cleanup = synaptics_reset;
1621 : : /* Synaptics can usually stay in sync without extra help */
1622 : 0 : psmouse->resync_time = 0;
1623 : :
1624 [ # # ]: 0 : if (SYN_CAP_PASS_THROUGH(priv->capabilities))
1625 : 0 : synaptics_pt_create(psmouse);
1626 : :
1627 : : /*
1628 : : * Toshiba's KBC seems to have trouble handling data from
1629 : : * Synaptics at full rate. Switch to a lower rate (roughly
1630 : : * the same rate as a standard PS/2 mouse).
1631 : : */
1632 [ # # ][ # # ]: 0 : if (psmouse->rate >= 80 && impaired_toshiba_kbc) {
1633 : 0 : psmouse_info(psmouse,
1634 : : "Toshiba %s detected, limiting rate to 40pps.\n",
1635 : : dmi_get_system_info(DMI_PRODUCT_NAME));
1636 : 0 : psmouse->rate = 40;
1637 : : }
1638 : :
1639 [ # # ][ # # ]: 0 : if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) {
1640 : 0 : err = device_create_file(&psmouse->ps2dev.serio->dev,
1641 : : &psmouse_attr_disable_gesture.dattr);
1642 [ # # ]: 0 : if (err) {
1643 : 0 : psmouse_err(psmouse,
1644 : : "Failed to create disable_gesture attribute (%d)",
1645 : : err);
1646 : 0 : goto init_fail;
1647 : : }
1648 : : }
1649 : :
1650 : : return 0;
1651 : :
1652 : : init_fail:
1653 : 0 : kfree(priv);
1654 : 0 : return err;
1655 : : }
1656 : :
1657 : 0 : int synaptics_init(struct psmouse *psmouse)
1658 : : {
1659 : 0 : return __synaptics_init(psmouse, true);
1660 : : }
1661 : :
1662 : 0 : int synaptics_init_relative(struct psmouse *psmouse)
1663 : : {
1664 : 0 : return __synaptics_init(psmouse, false);
1665 : : }
1666 : :
1667 : 0 : bool synaptics_supported(void)
1668 : : {
1669 : 0 : return true;
1670 : : }
1671 : :
1672 : : #else /* CONFIG_MOUSE_PS2_SYNAPTICS */
1673 : :
1674 : : void __init synaptics_module_init(void)
1675 : : {
1676 : : }
1677 : :
1678 : : int synaptics_init(struct psmouse *psmouse)
1679 : : {
1680 : : return -ENOSYS;
1681 : : }
1682 : :
1683 : : bool synaptics_supported(void)
1684 : : {
1685 : : return false;
1686 : : }
1687 : :
1688 : : #endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
|