summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/dkms_source_tree/Makefile2
-rw-r--r--usr/src/dkms_source_tree/input-mt.c307
-rw-r--r--usr/src/dkms_source_tree/input-mt.h56
-rw-r--r--usr/src/dkms_source_tree/synaptics.c247
-rw-r--r--usr/src/dkms_source_tree/synaptics.h10
5 files changed, 534 insertions, 88 deletions
diff --git a/usr/src/dkms_source_tree/Makefile b/usr/src/dkms_source_tree/Makefile
index 8a48755..e543a38 100644
--- a/usr/src/dkms_source_tree/Makefile
+++ b/usr/src/dkms_source_tree/Makefile
@@ -6,7 +6,7 @@
6 6
7obj-m += psmouse.o 7obj-m += psmouse.o
8 8
9psmouse-objs := psmouse-base.o synaptics.o 9psmouse-objs := psmouse-base.o synaptics.o input-mt.o
10 10
11psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o 11psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
12psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o 12psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
diff --git a/usr/src/dkms_source_tree/input-mt.c b/usr/src/dkms_source_tree/input-mt.c
new file mode 100644
index 0000000..236360f
--- /dev/null
+++ b/usr/src/dkms_source_tree/input-mt.c
@@ -0,0 +1,307 @@
1/*
2 * Input Multitouch Library
3 *
4 * Copyright (c) 2008-2010 Henrik Rydberg
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10
11#include "input-mt.h"
12
13
14#define TRKID_BITS 16
15#define TRKID_MAX ((1 << TRKID_BITS) - 1)
16#define TRKID_SGN (1 << (TRKID_BITS - 1))
17
18static int trkid; // destined for input_dev
19
20int input_mt_create_slots_new(struct input_dev *dev, unsigned int num_slots)
21{
22 int ret;
23
24 ret = input_mt_create_slots(dev, num_slots);
25 if (ret)
26 return ret;
27
28 input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
29
30 return 0;
31}
32
33/**
34 * input_mt_report_state() - report contact state
35 * @dev: input device with allocated MT slots
36 * @active: true if contact is active, false otherwise
37 *
38 * Reports an active touch via ABS_MT_TRACKING_ID. If active is
39 * true and the slot is currently inactive, a new tracking id is
40 * assigned to the slot.
41 */
42void input_mt_report_state(struct input_dev *dev, bool active)
43{
44 int id = -1;
45
46 if (dev->mt && active) {
47 id = input_mt_get_value(&dev->mt[dev->slot], ABS_MT_TRACKING_ID);
48 if (id < 0)
49 id = trkid++ & TRKID_MAX;
50 }
51
52 input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
53}
54
55/**
56 * input_mt_report_emulation() - common pointer emulation
57 * @dev: input device with allocated MT slots
58 *
59 * Performs legacy emulation emulation via BTN_TOUCH, etc.
60 */
61void input_mt_report_emulation(struct input_dev *dev)
62{
63 struct input_mt_slot *oldest = 0;
64 int oldid = -1;
65 int count = 0;
66 int i;
67
68 for (i = 0; i < dev->mtsize; ++i) {
69 struct input_mt_slot *slot = &dev->mt[i];
70 int id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
71
72 if (id < 0)
73 continue;
74
75 if (!oldest || ((id - oldid) & TRKID_SGN)) {
76 oldest = slot;
77 oldid = id;
78 }
79 count++;
80 }
81
82 input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
83 input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
84 input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
85 input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
86 input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count > 3);
87
88 if (oldest) {
89 int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
90 int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
91 int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
92
93 input_event(dev, EV_ABS, ABS_X, x);
94 input_event(dev, EV_ABS, ABS_Y, y);
95 input_event(dev, EV_ABS, ABS_PRESSURE, p);
96 } else {
97 input_event(dev, EV_ABS, ABS_PRESSURE, 0);
98 }
99}
100
101
102/* generated by mtdev-kernel - do not edit */
103static const u8 match_data[] = {
104 0, 0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 0, 0, 0, 1, 1,
105 1, 0, 0, 0, 1, 2, 1, 1, 0, 2, 2, 1, 2, 0, 0, 0,
106 1, 2, 3, 1, 1, 0, 2, 3, 2, 1, 2, 0, 3, 3, 1, 2,
107 3, 0, 0, 0, 1, 1, 1, 2, 1, 0, 0, 3, 0, 1, 1, 3,
108 1, 0, 2, 2, 3, 1, 2, 0, 0, 4, 0, 1, 2, 2, 4, 2,
109 1, 0, 0, 5, 0, 2, 1, 1, 5, 2, 0, 1, 1, 4, 1, 0,
110 2, 3, 2, 4, 1, 2, 0, 3, 3, 4, 1, 2, 3, 0, 0, 5,
111 0, 1, 2, 3, 2, 5, 2, 1, 0, 3, 3, 5, 2, 1, 3, 0,
112 0, 6, 0, 2, 1, 3, 1, 6, 2, 0, 1, 3, 3, 6, 2, 3,
113 1, 0, 0, 7, 0, 2, 3, 1, 1, 7, 2, 0, 3, 1, 2, 7,
114 2, 3, 0, 1, 0, 0, 1, 1, 2, 2, 1, 2, 1, 0, 0, 3,
115 0, 1, 1, 4, 2, 0, 3, 4, 2, 1, 0, 5, 0, 2, 2, 5,
116 1, 2, 2, 4, 6, 2, 1, 0, 1, 5, 6, 2, 0, 1, 2, 3,
117 7, 1, 2, 0, 0, 5, 7, 0, 2, 1, 1, 3, 8, 1, 0, 2,
118 0, 4, 8, 0, 1, 2, 2, 5, 8, 2, 1, 0, 3, 3, 5, 8,
119 2, 1, 3, 0, 1, 6, 8, 2, 0, 1, 3, 3, 6, 8, 2, 3,
120 1, 0, 1, 7, 8, 2, 0, 3, 1, 2, 7, 8, 2, 3, 0, 1,
121 2, 4, 9, 1, 2, 0, 3, 3, 4, 9, 1, 2, 3, 0, 0, 6,
122 9, 0, 2, 1, 3, 3, 6, 9, 3, 2, 1, 0, 0, 7, 9, 0,
123 2, 3, 1, 2, 7, 9, 3, 2, 0, 1, 1, 4, 10, 1, 0, 2,
124 3, 3, 4, 10, 1, 3, 2, 0, 0, 5, 10, 0, 1, 2, 3, 3,
125 5, 10, 3, 1, 2, 0, 0, 7, 10, 0, 3, 2, 1, 1, 7, 10,
126 3, 0, 2, 1, 1, 4, 11, 1, 0, 3, 2, 2, 4, 11, 1, 3,
127 0, 2, 0, 5, 11, 0, 1, 3, 2, 2, 5, 11, 3, 1, 0, 2,
128 0, 6, 11, 0, 3, 1, 2, 1, 6, 11, 3, 0, 1, 2, 0, 0,
129 1, 1, 2, 2, 3, 3, 1, 2, 1, 0, 0, 3, 0, 1, 1, 4,
130 2, 0, 3, 4, 2, 1, 0, 5, 0, 2, 2, 5, 1, 2, 1, 6,
131 3, 0, 3, 6, 3, 1, 5, 6, 3, 2, 0, 7, 0, 3, 2, 7,
132 1, 3, 4, 7, 2, 3, 2, 4, 6, 2, 1, 0, 1, 5, 6, 2,
133 0, 1, 2, 3, 7, 1, 2, 0, 0, 5, 7, 0, 2, 1, 1, 3,
134 8, 1, 0, 2, 0, 4, 8, 0, 1, 2, 2, 4, 9, 3, 1, 0,
135 1, 5, 9, 3, 0, 1, 2, 7, 9, 3, 2, 0, 5, 7, 9, 3,
136 2, 1, 1, 8, 9, 3, 0, 2, 4, 8, 9, 3, 1, 2, 2, 3,
137 10, 1, 3, 0, 0, 5, 10, 0, 3, 1, 2, 6, 10, 2, 3, 0,
138 5, 6, 10, 2, 3, 1, 0, 8, 10, 0, 3, 2, 3, 8, 10, 1,
139 3, 2, 1, 3, 11, 1, 0, 3, 0, 4, 11, 0, 1, 3, 1, 6,
140 11, 2, 0, 3, 4, 6, 11, 2, 1, 3, 0, 7, 11, 0, 2, 3,
141 3, 7, 11, 1, 2, 3, 3, 6, 9, 12, 3, 2, 1, 0, 2, 7,
142 9, 12, 3, 2, 0, 1, 3, 5, 10, 12, 3, 1, 2, 0, 1, 7,
143 10, 12, 3, 0, 2, 1, 2, 5, 11, 12, 3, 1, 0, 2, 1, 6,
144 11, 12, 3, 0, 1, 2, 3, 6, 8, 13, 2, 3, 1, 0, 2, 7,
145 8, 13, 2, 3, 0, 1, 3, 4, 10, 13, 1, 3, 2, 0, 0, 7,
146 10, 13, 0, 3, 2, 1, 2, 4, 11, 13, 1, 3, 0, 2, 0, 6,
147 11, 13, 0, 3, 1, 2, 3, 5, 8, 14, 2, 1, 3, 0, 1, 7,
148 8, 14, 2, 0, 3, 1, 3, 4, 9, 14, 1, 2, 3, 0, 0, 7,
149 9, 14, 0, 2, 3, 1, 1, 4, 11, 14, 1, 0, 3, 2, 0, 5,
150 11, 14, 0, 1, 3, 2, 2, 5, 8, 15, 2, 1, 0, 3, 1, 6,
151 8, 15, 2, 0, 1, 3, 2, 4, 9, 15, 1, 2, 0, 3, 0, 6,
152 9, 15, 0, 2, 1, 3, 1, 4, 10, 15, 1, 0, 2, 3, 0, 5,
153 10, 15, 0, 1, 2, 3,
154};
155
156/* generated by mtdev-kernel - do not edit */
157static const int match_index[][5] = {
158 { 0, 0, 1, 3, 6 },
159 { 10, 10, 12, 18, 30 },
160 { 50, 50, 54, 62, 92 },
161 { 164, 164, 170, 194, 230 },
162 { 398, 398, 406, 454, 598 },
163 { 790 }
164};
165
166static void set_dist(u32 *dist,
167 const struct trk_coord *b1, const struct trk_coord *e1,
168 const struct trk_coord *b2, const struct trk_coord *e2)
169{
170 const struct trk_coord *p, *q;
171
172 for (p = b1; p != e1; p++)
173 for (q = b2; q != e2; q++)
174 *dist++ = abs(q->x - p->x) + abs(q->y - p->y);
175}
176
177const u8 *match_four(const struct trk_coord *old, int nslot,
178 const struct trk_coord *pos, int npos)
179{
180 u32 d[16], obj, t;
181 const u8 *p, *b, *e;
182 const int *at;
183
184 set_dist(d, old, old + nslot, pos, pos + npos);
185
186 at = &match_index[nslot][npos];
187 b = &match_data[at[0]];
188 e = &match_data[at[1]];
189
190 obj = UINT_MAX, p = b;
191
192 switch (min(nslot, npos)) {
193 case 1:
194 for (; b != e; b += npos) {
195 t = d[*b++];
196 if (t < obj)
197 obj = t, p = b;
198 }
199 break;
200 case 2:
201 for (; b != e; b += npos) {
202 t = d[*b++], t += d[*b++];
203 if (t < obj)
204 obj = t, p = b;
205 }
206 break;
207 case 3:
208 for (; b != e; b += npos) {
209 t = d[*b++], t += d[*b++], t += d[*b++];
210 if (t < obj)
211 obj = t, p = b;
212 }
213 break;
214 case 4:
215 for (; b != e; b += npos) {
216 t = d[*b++], t += d[*b++], t += d[*b++], t += d[*b++];
217 if (t < obj)
218 obj = t, p = b;
219 }
220 break;
221 }
222
223 return p;
224}
225
226/**
227 * input_mt_assign_slots_by_coord() - perform a best-match assignment
228 * @dev: input device with allocated MT slots
229 * @slots: the slot assignment to be filled
230 * @coords: the coordinate array to match
231 * @num_coords: number of coordinates
232 *
233 * Performs a best match against the current contacts and returns
234 * the slot assignment list. New contacts are assigned to unused
235 * slots.
236 *
237 * Returns zero on success, or negative error in case of failure.
238 */
239int input_mt_assign_slots_by_coord(struct input_dev *dev, int *slots,
240 const struct trk_coord *coords,
241 int num_coords)
242{
243 struct trk_coord old[4];
244 int old2slot[4], nold, i;
245 const u8 *p;
246
247 if (!dev->mt)
248 return -ENXIO;
249 if (dev->mtsize < 2 || dev->mtsize > 4)
250 return -ENXIO;
251 if (num_coords > dev->mtsize)
252 return -EINVAL;
253 if (num_coords < 1)
254 return 0;
255
256 nold = 0;
257 for (i = 0; i < dev->mtsize; i++) {
258 const struct input_mt_slot *mt = &dev->mt[i];
259 if (input_mt_get_value(mt, ABS_MT_TRACKING_ID) < 0)
260 continue;
261 old[nold].x = input_mt_get_value(mt, ABS_MT_POSITION_X);
262 old[nold].y = input_mt_get_value(mt, ABS_MT_POSITION_Y);
263 old2slot[nold++] = i;
264 }
265
266 p = match_four(old, nold, coords, num_coords);
267
268 for (i = 0; i < dev->mtsize; i++)
269 if (input_mt_get_value(&dev->mt[i], ABS_MT_TRACKING_ID) < 0)
270 old2slot[nold++] = i;
271
272 for (i = 0; i < num_coords; i++)
273 slots[i] = old2slot[p[i]];
274
275 return 0;
276}
277
278
279/**
280 * input_mt_sync_slot_complement() - send touchup for remaining slots
281 * @dev: input device with allocated MT slots
282 * @slots: the slot assignment to be filled
283 * @coords: the coordinate array to match
284 * @num_coords: number of coordinates
285 *
286 * Performs a best match against the current contacts and returns
287 * the slot assignment list. New contacts are assigned to unused
288 * slots.
289 *
290 * Returns zero on success, or negative error in case of failure.
291 */
292void input_mt_sync_slot_complement(struct input_dev *dev,
293 const int *slots, int num_slots)
294{
295 unsigned long mask = 0;
296 int i;
297
298 for (i = 0; i < num_slots; i++)
299 mask |= BIT(slots[i]);
300
301 for (i = 0; i < dev->mtsize; i++) {
302 if (mask & BIT(i))
303 continue;
304 input_mt_slot(dev, i);
305 input_mt_report_state(dev, false);
306 }
307}
diff --git a/usr/src/dkms_source_tree/input-mt.h b/usr/src/dkms_source_tree/input-mt.h
new file mode 100644
index 0000000..fdee06e
--- /dev/null
+++ b/usr/src/dkms_source_tree/input-mt.h
@@ -0,0 +1,56 @@
1#ifndef _INPUT_MT_H
2#define _INPUT_MT_H
3
4/*
5 * Input Multitouch Library
6 *
7 * Copyright (c) 2010 Henrik Rydberg
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 */
13
14#include <linux/input.h>
15
16/**
17 * struct trk_coord - contact coordinate
18 * @x: horizontal coordinate
19 * @y: vertical coordinate
20 */
21struct trk_coord {
22 int x;
23 int y;
24};
25
26int input_mt_create_slots_new(struct input_dev *dev, unsigned int num_slots);
27
28int input_mt_assign_slots_by_coord(struct input_dev *dev, int *slots,
29 const struct trk_coord *coords,
30 int num_coords);
31
32void input_mt_sync_slot_complement(struct input_dev *dev,
33 const int *slots, int num_slots);
34
35void input_mt_report_state(struct input_dev *dev, bool active);
36void input_mt_report_emulation(struct input_dev *dev);
37
38static inline int input_mt_get_value(const struct input_mt_slot *slot,
39 unsigned code)
40{
41 return slot->abs[code - ABS_MT_FIRST];
42}
43
44static inline bool input_mt_get_state(struct input_dev *dev, int slot)
45{
46 return dev->mt &&
47 input_mt_get_value(&dev->mt[slot], ABS_MT_TRACKING_ID) >= 0;
48}
49
50static inline void input_abs_set_res(struct input_dev *dev,
51 unsigned int axis, int val)
52{
53 dev->absres[axis] = val;
54}
55
56#endif
diff --git a/usr/src/dkms_source_tree/synaptics.c b/usr/src/dkms_source_tree/synaptics.c
index ae9891c..c19d39f 100644
--- a/usr/src/dkms_source_tree/synaptics.c
+++ b/usr/src/dkms_source_tree/synaptics.c
@@ -279,6 +279,24 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
279 synaptics_mode_cmd(psmouse, priv->mode); 279 synaptics_mode_cmd(psmouse, priv->mode);
280} 280}
281 281
282static int synaptics_set_multitouch_mode(struct psmouse *psmouse)
283{
284 static unsigned char param = 0xc8;
285 struct synaptics_data *priv = psmouse->private;
286
287 if (!SYN_CAP_MULTITOUCH(priv->ext_cap_0c))
288 return 0;
289
290 if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
291 return -1;
292 if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
293 return -1;
294
295 priv->multitouch = 1;
296 printk(KERN_INFO "Synaptics: Multitouch mode enabled\n");
297 return 0;
298}
299
282/***************************************************************************** 300/*****************************************************************************
283 * Synaptics pass-through PS/2 port support 301 * Synaptics pass-through PS/2 port support
284 ****************************************************************************/ 302 ****************************************************************************/
@@ -294,7 +312,29 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
294 return 0; 312 return 0;
295} 313}
296 314
297static inline int synaptics_is_pt_packet(unsigned char *buf) 315static int synaptics_pt_start(struct serio *serio)
316{
317 struct psmouse *parent = serio_get_drvdata(serio->parent);
318 struct synaptics_data *priv = parent->private;
319
320 serio_pause_rx(parent->ps2dev.serio);
321 priv->pt_port = serio;
322 serio_continue_rx(parent->ps2dev.serio);
323
324 return 0;
325}
326
327static void synaptics_pt_stop(struct serio *serio)
328{
329 struct psmouse *parent = serio_get_drvdata(serio->parent);
330 struct synaptics_data *priv = parent->private;
331
332 serio_pause_rx(parent->ps2dev.serio);
333 priv->pt_port = NULL;
334 serio_continue_rx(parent->ps2dev.serio);
335}
336
337static int synaptics_is_pt_packet(unsigned char *buf)
298{ 338{
299 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; 339 return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
300} 340}
@@ -315,9 +355,8 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
315 355
316static void synaptics_pt_activate(struct psmouse *psmouse) 356static void synaptics_pt_activate(struct psmouse *psmouse)
317{ 357{
318 struct serio *ptport = psmouse->ps2dev.serio->child;
319 struct psmouse *child = serio_get_drvdata(ptport);
320 struct synaptics_data *priv = psmouse->private; 358 struct synaptics_data *priv = psmouse->private;
359 struct psmouse *child = serio_get_drvdata(priv->pt_port);
321 360
322 /* adjust the touchpad to child's choice of protocol */ 361 /* adjust the touchpad to child's choice of protocol */
323 if (child) { 362 if (child) {
@@ -345,6 +384,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
345 strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); 384 strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
346 strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); 385 strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
347 serio->write = synaptics_pt_write; 386 serio->write = synaptics_pt_write;
387 serio->start = synaptics_pt_start;
388 serio->stop = synaptics_pt_stop;
348 serio->parent = psmouse->ps2dev.serio; 389 serio->parent = psmouse->ps2dev.serio;
349 390
350 psmouse->pt_activate = synaptics_pt_activate; 391 psmouse->pt_activate = synaptics_pt_activate;
@@ -357,62 +398,38 @@ static void synaptics_pt_create(struct psmouse *psmouse)
357 * Functions to interpret the absolute mode packets 398 * Functions to interpret the absolute mode packets
358 ****************************************************************************/ 399 ****************************************************************************/
359 400
360/* left and right clickpad button ranges; 401static int synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
361 * the gap between them is interpreted as a middle-button click
362 */
363#define CLICKPAD_LEFT_BTN_X \
364 ((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL)
365#define CLICKPAD_RIGHT_BTN_X \
366 ((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL)
367
368/* handle clickpad events */
369static void clickpad_process_packet(struct synaptics_data *priv,
370 struct synaptics_hw_state *hw)
371{
372 /* clickpad mode reports Y range from 0 to YMAX_NOMINAL,
373 * where the area Y < YMIN_NOMINAL is used as click buttons
374 */
375 if (hw->y < YMIN_NOMINAL) {
376 /* button area */
377 hw->z = 0; /* don't move pointer */
378 /* clickpad reports only the middle button, and we need
379 * to fake left/right buttons depending on the touch position
380 */
381 if (hw->middle) { /* clicked? */
382 hw->middle = 0;
383 if (hw->x < CLICKPAD_LEFT_BTN_X)
384 hw->left = 1;
385 else if (hw->x > CLICKPAD_RIGHT_BTN_X)
386 hw->right = 1;
387 else
388 hw->middle = 1;
389 }
390 } else if (hw->middle) {
391 /* dragging */
392 hw->left = priv->prev_hw.left;
393 hw->right = priv->prev_hw.right;
394 hw->middle = priv->prev_hw.middle;
395 }
396 priv->prev_hw = *hw;
397}
398
399static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
400{ 402{
401 memset(hw, 0, sizeof(struct synaptics_hw_state)); 403 memset(hw, 0, sizeof(struct synaptics_hw_state));
402 404
403 if (SYN_MODEL_NEWABS(priv->model_id)) { 405 if (SYN_MODEL_NEWABS(priv->model_id)) {
404 hw->x = (((buf[3] & 0x10) << 8) |
405 ((buf[1] & 0x0f) << 8) |
406 buf[4]);
407 hw->y = (((buf[3] & 0x20) << 7) |
408 ((buf[1] & 0xf0) << 4) |
409 buf[5]);
410
411 hw->z = buf[2];
412 hw->w = (((buf[0] & 0x30) >> 2) | 406 hw->w = (((buf[0] & 0x30) >> 2) |
413 ((buf[0] & 0x04) >> 1) | 407 ((buf[0] & 0x04) >> 1) |
414 ((buf[3] & 0x04) >> 2)); 408 ((buf[3] & 0x04) >> 2));
415 409
410 if (priv->multitouch && hw->w == 2) {
411 /* Multitouch data is half normal resolution */
412 hw->x = (((buf[4] & 0x0f) << 8) |
413 buf[1]) << 1;
414 hw->y = (((buf[4] & 0xf0) << 4) |
415 buf[2]) << 1;
416
417 hw->z = ((buf[3] & 0x30) |
418 (buf[5] & 0x0f)) << 1;
419
420 /* Only look at x, y, and z for MT */
421 return 1;
422 } else {
423 hw->x = (((buf[3] & 0x10) << 8) |
424 ((buf[1] & 0x0f) << 8) |
425 buf[4]);
426 hw->y = (((buf[3] & 0x20) << 7) |
427 ((buf[1] & 0xf0) << 4) |
428 buf[5]);
429
430 hw->z = buf[2];
431 }
432
416 hw->left = (buf[0] & 0x01) ? 1 : 0; 433 hw->left = (buf[0] & 0x01) ? 1 : 0;
417 hw->right = (buf[0] & 0x02) ? 1 : 0; 434 hw->right = (buf[0] & 0x02) ? 1 : 0;
418 435
@@ -468,6 +485,8 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
468 hw->left = (buf[0] & 0x01) ? 1 : 0; 485 hw->left = (buf[0] & 0x01) ? 1 : 0;
469 hw->right = (buf[0] & 0x02) ? 1 : 0; 486 hw->right = (buf[0] & 0x02) ? 1 : 0;
470 } 487 }
488
489 return 0;
471} 490}
472 491
473/* 492/*
@@ -482,10 +501,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
482 int finger_width; 501 int finger_width;
483 int i; 502 int i;
484 503
485 synaptics_parse_hw_state(psmouse->packet, priv, &hw); 504 if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) {
486 505 priv->mt_pkt = 1;
487 if (SYN_CAP_CLICKPAD(priv->ext_cap)) 506 priv->mt = hw;
488 clickpad_process_packet(priv, &hw); 507 return;
508 }
489 509
490 if (hw.scroll) { 510 if (hw.scroll) {
491 priv->scroll += hw.scroll; 511 priv->scroll += hw.scroll;
@@ -513,7 +533,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
513 if (SYN_CAP_EXTENDED(priv->capabilities)) { 533 if (SYN_CAP_EXTENDED(priv->capabilities)) {
514 switch (hw.w) { 534 switch (hw.w) {
515 case 0 ... 1: 535 case 0 ... 1:
516 if (SYN_CAP_MULTIFINGER(priv->capabilities)) 536 if (SYN_CAP_MULTIFINGER(priv->capabilities) ||
537 priv->multitouch)
517 num_fingers = hw.w + 2; 538 num_fingers = hw.w + 2;
518 break; 539 break;
519 case 2: 540 case 2:
@@ -531,28 +552,64 @@ static void synaptics_process_packet(struct psmouse *psmouse)
531 finger_width = 0; 552 finger_width = 0;
532 } 553 }
533 554
534 /* Post events 555 if (priv->multitouch) {
535 * BTN_TOUCH has to be first as mousedev relies on it when doing 556 struct trk_coord pos[2];
536 * absolute -> relative conversion 557 int slots[2];
537 */ 558 int npos;
538 if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); 559
539 if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); 560 pos[0].x = hw.x;
561 pos[0].y = YMAX_NOMINAL + YMIN_NOMINAL - hw.y;
562 pos[1].x = priv->mt.x;
563 pos[1].y = YMAX_NOMINAL + YMIN_NOMINAL - priv->mt.y;
564 npos = priv->mt_pkt ? 2 : 1;
565 input_mt_assign_slots_by_coord(dev, slots, pos, npos);
566
567 for (i = 0; i < npos; i++) {
568 int x = pos[i].x;
569 int y = pos[i].y;
570 int z = i == 0 ? hw.z : priv->mt.z;
571 int s = z > 0 && x > 1;
572
573 input_mt_slot(dev, slots[i]);
574 input_mt_report_state(dev, s);
575
576 if (s) {
577 input_report_abs(dev, ABS_MT_POSITION_X, x);
578 input_report_abs(dev, ABS_MT_POSITION_Y, y);
579 input_report_abs(dev, ABS_MT_PRESSURE, z);
580 }
581 }
540 582
541 if (hw.z > 0) { 583 input_mt_sync_slot_complement(dev, slots, npos);
542 input_report_abs(dev, ABS_X, hw.x); 584 input_mt_report_emulation(dev);
543 input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); 585 } else {
586
587 /* Post events
588 * BTN_TOUCH has to be first as mousedev relies on it when doing
589 * absolute -> relative conversion
590 */
591 if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
592 if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
593
594 if (hw.z > 0) {
595 input_report_abs(dev, ABS_X, hw.x);
596 input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
597 }
598 input_report_abs(dev, ABS_PRESSURE, hw.z);
599
600 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
601
602 if (SYN_CAP_MULTIFINGER(priv->capabilities) || priv->multitouch) {
603 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
604 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
605 }
544 } 606 }
545 input_report_abs(dev, ABS_PRESSURE, hw.z);
546 607
547 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
548 input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
549 input_report_key(dev, BTN_LEFT, hw.left); 608 input_report_key(dev, BTN_LEFT, hw.left);
550 input_report_key(dev, BTN_RIGHT, hw.right); 609 input_report_key(dev, BTN_RIGHT, hw.right);
551 610
552 if (SYN_CAP_MULTIFINGER(priv->capabilities)) { 611 if (SYN_CAP_PALMDETECT(priv->capabilities))
553 input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); 612 input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
554 input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
555 }
556 613
557 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) 614 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
558 input_report_key(dev, BTN_MIDDLE, hw.middle); 615 input_report_key(dev, BTN_MIDDLE, hw.middle);
@@ -566,6 +623,8 @@ static void synaptics_process_packet(struct psmouse *psmouse)
566 input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i)); 623 input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
567 624
568 input_sync(dev); 625 input_sync(dev);
626
627 priv->mt_pkt = 0;
569} 628}
570 629
571static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) 630static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
@@ -618,9 +677,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
618 if (unlikely(priv->pkt_type == SYN_NEWABS)) 677 if (unlikely(priv->pkt_type == SYN_NEWABS))
619 priv->pkt_type = synaptics_detect_pkt_type(psmouse); 678 priv->pkt_type = synaptics_detect_pkt_type(psmouse);
620 679
621 if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { 680 if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
622 if (psmouse->ps2dev.serio->child) 681 synaptics_is_pt_packet(psmouse->packet)) {
623 synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet); 682 if (priv->pt_port)
683 synaptics_pass_pt_packet(priv->pt_port, psmouse->packet);
624 } else 684 } else
625 synaptics_process_packet(psmouse); 685 synaptics_process_packet(psmouse);
626 686
@@ -644,7 +704,18 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
644 input_set_abs_params(dev, ABS_Y, 704 input_set_abs_params(dev, ABS_Y,
645 YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); 705 YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
646 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); 706 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
647 __set_bit(ABS_TOOL_WIDTH, dev->absbit); 707
708 if (priv->multitouch) {
709 input_mt_create_slots_new(dev, 2);
710 input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL,
711 priv->x_max ?: XMAX_NOMINAL, 0, 0);
712 input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL,
713 priv->y_max ?: YMAX_NOMINAL, 0, 0);
714 input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
715 }
716
717 if (SYN_CAP_PALMDETECT(priv->capabilities))
718 input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
648 719
649 __set_bit(EV_KEY, dev->evbit); 720 __set_bit(EV_KEY, dev->evbit);
650 __set_bit(BTN_TOUCH, dev->keybit); 721 __set_bit(BTN_TOUCH, dev->keybit);
@@ -652,7 +723,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
652 __set_bit(BTN_LEFT, dev->keybit); 723 __set_bit(BTN_LEFT, dev->keybit);
653 __set_bit(BTN_RIGHT, dev->keybit); 724 __set_bit(BTN_RIGHT, dev->keybit);
654 725
655 if (SYN_CAP_MULTIFINGER(priv->capabilities)) { 726 if (SYN_CAP_MULTIFINGER(priv->capabilities) | priv->multitouch) {
656 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); 727 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
657 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); 728 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
658 } 729 }
@@ -673,8 +744,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
673 __clear_bit(REL_X, dev->relbit); 744 __clear_bit(REL_X, dev->relbit);
674 __clear_bit(REL_Y, dev->relbit); 745 __clear_bit(REL_Y, dev->relbit);
675 746
676 dev->absres[ABS_X] = priv->x_res; 747 input_abs_set_res(dev, ABS_X, priv->x_res);
677 dev->absres[ABS_Y] = priv->y_res; 748 input_abs_set_res(dev, ABS_Y, priv->y_res);
678 749
679 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { 750 if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
680 /* Clickpads report only left button */ 751 /* Clickpads report only left button */
@@ -716,6 +787,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
716 return -1; 787 return -1;
717 } 788 }
718 789
790 if (synaptics_set_multitouch_mode(psmouse)) {
791 printk(KERN_ERR "Unable to initialize Synaptics Multitouch.\n");
792 return -1;
793 }
794
719 return 0; 795 return 0;
720} 796}
721 797
@@ -769,7 +845,7 @@ int synaptics_init(struct psmouse *psmouse)
769 845
770 psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); 846 psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
771 if (!priv) 847 if (!priv)
772 return -1; 848 return -ENOMEM;
773 849
774 psmouse_reset(psmouse); 850 psmouse_reset(psmouse);
775 851
@@ -783,6 +859,11 @@ int synaptics_init(struct psmouse *psmouse)
783 goto init_fail; 859 goto init_fail;
784 } 860 }
785 861
862 if (synaptics_set_multitouch_mode(psmouse)) {
863 printk(KERN_ERR "Unable to initialize Synaptics Multitouch.\n");
864 goto init_fail;
865 }
866
786 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; 867 priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
787 868
788 printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", 869 printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
@@ -790,12 +871,6 @@ int synaptics_init(struct psmouse *psmouse)
790 SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), 871 SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
791 priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c); 872 priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
792 873
793 if (SYN_CAP_CLICKPAD(priv->ext_cap)) {
794 printk(KERN_INFO "Synaptics: Clickpad mode enabled\n");
795 /* force to enable the middle button */
796 priv->capabilities |= (1 << 18);
797 }
798
799 set_input_params(psmouse->dev, priv); 874 set_input_params(psmouse->dev, priv);
800 875
801 /* 876 /*
diff --git a/usr/src/dkms_source_tree/synaptics.h b/usr/src/dkms_source_tree/synaptics.h
index 80907d0..c3653e1 100644
--- a/usr/src/dkms_source_tree/synaptics.h
+++ b/usr/src/dkms_source_tree/synaptics.h
@@ -6,6 +6,8 @@
6 * the Free Software Foundation. 6 * the Free Software Foundation.
7 */ 7 */
8 8
9#include "input-mt.h"
10
9#ifndef _SYNAPTICS_H 11#ifndef _SYNAPTICS_H
10#define _SYNAPTICS_H 12#define _SYNAPTICS_H
11 13
@@ -53,6 +55,7 @@
53#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) 55#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
54#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100) 56#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
55#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) 57#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000)
58#define SYN_CAP_MULTITOUCH(ex0c) ((ex0c) & 0x080000)
56 59
57/* synaptics modes query bits */ 60/* synaptics modes query bits */
58#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) 61#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -110,7 +113,12 @@ struct synaptics_data {
110 unsigned char pkt_type; /* packet type - old, new, etc */ 113 unsigned char pkt_type; /* packet type - old, new, etc */
111 unsigned char mode; /* current mode byte */ 114 unsigned char mode; /* current mode byte */
112 int scroll; 115 int scroll;
113 struct synaptics_hw_state prev_hw; 116
117 struct serio *pt_port; /* Pass-through serio port */
118
119 int multitouch; /* device provides MT data */
120 int mt_pkt; /* received MT packet */
121 struct synaptics_hw_state mt; /* current MT packet */
114}; 122};
115 123
116void synaptics_module_init(void); 124void synaptics_module_init(void);