diff options
Diffstat (limited to 'usr')
| -rw-r--r-- | usr/src/dkms_source_tree/Makefile | 2 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/input-mt.c | 307 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/input-mt.h | 56 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/synaptics.c | 247 | ||||
| -rw-r--r-- | usr/src/dkms_source_tree/synaptics.h | 10 |
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 | ||
| 7 | obj-m += psmouse.o | 7 | obj-m += psmouse.o |
| 8 | 8 | ||
| 9 | psmouse-objs := psmouse-base.o synaptics.o | 9 | psmouse-objs := psmouse-base.o synaptics.o input-mt.o |
| 10 | 10 | ||
| 11 | psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o | 11 | psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o |
| 12 | psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o | 12 | psmouse-$(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 | |||
| 18 | static int trkid; // destined for input_dev | ||
| 19 | |||
| 20 | int 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 | */ | ||
| 42 | void 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 | */ | ||
| 61 | void 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 */ | ||
| 103 | static 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 */ | ||
| 157 | static 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 | |||
| 166 | static 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 | |||
| 177 | const 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 | */ | ||
| 239 | int 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 | */ | ||
| 292 | void 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 | */ | ||
| 21 | struct trk_coord { | ||
| 22 | int x; | ||
| 23 | int y; | ||
| 24 | }; | ||
| 25 | |||
| 26 | int input_mt_create_slots_new(struct input_dev *dev, unsigned int num_slots); | ||
| 27 | |||
| 28 | int input_mt_assign_slots_by_coord(struct input_dev *dev, int *slots, | ||
| 29 | const struct trk_coord *coords, | ||
| 30 | int num_coords); | ||
| 31 | |||
| 32 | void input_mt_sync_slot_complement(struct input_dev *dev, | ||
| 33 | const int *slots, int num_slots); | ||
| 34 | |||
| 35 | void input_mt_report_state(struct input_dev *dev, bool active); | ||
| 36 | void input_mt_report_emulation(struct input_dev *dev); | ||
| 37 | |||
| 38 | static 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 | |||
| 44 | static 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 | |||
| 50 | static 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 | ||
| 282 | static 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, ¶m, 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 | ||
| 297 | static inline int synaptics_is_pt_packet(unsigned char *buf) | 315 | static 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 | |||
| 327 | static 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 | |||
| 337 | static 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 | ||
| 316 | static void synaptics_pt_activate(struct psmouse *psmouse) | 356 | static 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; | 401 | static 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 */ | ||
| 369 | static 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 | |||
| 399 | static 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 | ||
| 571 | static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) | 630 | static 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 | ||
| 116 | void synaptics_module_init(void); | 124 | void synaptics_module_init(void); |
