/[linux-patches]/genpatches-2.6/tags/3.0-30/2620_Input-ALPS-Add-support-for-protocol-versions-3-and-4.patch
Gentoo

Contents of /genpatches-2.6/tags/3.0-30/2620_Input-ALPS-Add-support-for-protocol-versions-3-and-4.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2206 - (show annotations) (download)
Mon Sep 17 18:58:14 2012 UTC (2 years, 3 months ago) by mpagano
File size: 30460 byte(s)
3.0-30 release
1 From 0d2064f77fc5b1d983a0b6bf39b08c36d7b58d68 Mon Sep 17 00:00:00 2001
2 From: Seth Forshee <seth.forshee@canonical.com>
3 Date: Wed, 14 Sep 2011 11:40:39 -0500
4 Subject: [PATCH 5/8] Input: ALPS - Add support for protocol versions 3 and 4
5
6 This patch adds support for two ALPS touchpad protocols not
7 supported currently by the driver, which I am arbitrarily naming
8 version 3 and version 4. Support is single-touch only at this time,
9 although both protocols are capable of limited multitouch support.
10
11 Thanks to Andrew Skalski, who did the initial reverse-engineering
12 of the v3 protocol.
13
14 Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
15 ---
16 drivers/input/mouse/alps.c | 787 +++++++++++++++++++++++++++++++++++++++++---
17 drivers/input/mouse/alps.h | 14 +
18 2 files changed, 763 insertions(+), 38 deletions(-)
19
20 diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
21 index 14d1f64..8419c14 100644
22 --- a/drivers/input/mouse/alps.c
23 +++ b/drivers/input/mouse/alps.c
24 @@ -30,6 +30,50 @@
25 #define dbg(format, arg...) do {} while (0)
26 #endif
27
28 +/*
29 + * Definitions for ALPS version 3 and 4 command mode protocol
30 + */
31 +#define ALPS_CMD_NIBBLE_10 0x01f2
32 +
33 +static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
34 + { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
35 + { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
36 + { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
37 + { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
38 + { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
39 + { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
40 + { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
41 + { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
42 + { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
43 + { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
44 + { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
45 + { PSMOUSE_CMD_SETRES, 0x00 }, /* b */
46 + { PSMOUSE_CMD_SETRES, 0x01 }, /* c */
47 + { PSMOUSE_CMD_SETRES, 0x02 }, /* d */
48 + { PSMOUSE_CMD_SETRES, 0x03 }, /* e */
49 + { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
50 +};
51 +
52 +static const struct alps_nibble_commands alps_v4_nibble_commands[] = {
53 + { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */
54 + { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
55 + { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
56 + { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
57 + { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
58 + { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
59 + { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
60 + { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
61 + { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
62 + { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
63 + { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
64 + { PSMOUSE_CMD_SETRES, 0x00 }, /* b */
65 + { PSMOUSE_CMD_SETRES, 0x01 }, /* c */
66 + { PSMOUSE_CMD_SETRES, 0x02 }, /* d */
67 + { PSMOUSE_CMD_SETRES, 0x03 }, /* e */
68 + { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
69 +};
70 +
71 +
72 #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
73 #define ALPS_PASS 0x04 /* device has a pass-through port */
74
75 @@ -41,30 +85,33 @@
76 6-byte ALPS packet */
77
78 static const struct alps_model_info alps_model_data[] = {
79 - { { 0x32, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
80 - { { 0x33, 0x02, 0x0a }, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
81 - { { 0x53, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
82 - { { 0x53, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
83 - { { 0x60, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
84 - { { 0x63, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
85 - { { 0x63, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
86 - { { 0x63, 0x02, 0x28 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
87 - { { 0x63, 0x02, 0x3c }, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
88 - { { 0x63, 0x02, 0x50 }, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
89 - { { 0x63, 0x02, 0x64 }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
90 - { { 0x63, 0x03, 0xc8 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
91 - { { 0x73, 0x00, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
92 - { { 0x73, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
93 - { { 0x73, 0x02, 0x14 }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
94 - { { 0x20, 0x02, 0x0e }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
95 - { { 0x22, 0x02, 0x0a }, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
96 - { { 0x22, 0x02, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
97 + { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
98 + { { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
99 + { { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
100 + { { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
101 + { { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
102 + { { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
103 + { { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
104 + { { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
105 + { { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
106 + { { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
107 + { { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
108 + { { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
109 + { { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
110 + { { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
111 + { { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
112 + { { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
113 + { { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
114 + { { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
115 /* Dell Latitude E5500, E6400, E6500, Precision M4400 */
116 - { { 0x62, 0x02, 0x14 }, ALPS_PROTO_V2, 0xcf, 0xcf,
117 + { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
118 ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
119 - { { 0x73, 0x02, 0x50 }, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
120 - { { 0x52, 0x01, 0x14 }, ALPS_PROTO_V2, 0xff, 0xff,
121 - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
122 + { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
123 + { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
124 + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
125 + { { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
126 + { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
127 + { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
128 };
129
130 /*
131 @@ -108,7 +155,7 @@ static void alps_report_buttons(struct psmouse *psmouse,
132 input_sync(dev2);
133 }
134
135 -static void alps_process_packet(struct psmouse *psmouse)
136 +static void alps_process_packet_v1_v2(struct psmouse *psmouse)
137 {
138 struct alps_data *priv = psmouse->private;
139 const struct alps_model_info *model = priv->i;
140 @@ -210,6 +257,226 @@ static void alps_process_packet(struct psmouse *psmouse)
141 input_sync(dev);
142 }
143
144 +static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
145 +{
146 + struct alps_data *priv = psmouse->private;
147 + unsigned char *packet = psmouse->packet;
148 + struct input_dev *dev = priv->dev2;
149 + int x, y, z, left, right, middle;
150 +
151 + /* Sanity check packet */
152 + if (!(packet[0] & 0x40)) {
153 + pr_debug("alps.c: Bad trackstick packet, discarding\n");
154 + return;
155 + }
156 +
157 + /*
158 + * There's a special packet that seems to indicate the end
159 + * of a stream of trackstick data. Filter these out.
160 + */
161 + if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f)
162 + return;
163 +
164 + x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f));
165 + y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f));
166 + z = (packet[4] & 0x7c) >> 2;
167 +
168 + /*
169 + * The x and y values tend to be quite large, and when used
170 + * alone the trackstick is difficult to use. Scale them down
171 + * to compensate.
172 + */
173 + x /= 8;
174 + y /= 8;
175 +
176 + input_report_rel(dev, REL_X, x);
177 + input_report_rel(dev, REL_Y, -y);
178 +
179 + /*
180 + * Most ALPS models report the trackstick buttons in the touchpad
181 + * packets, but a few report them here. No reliable way has been
182 + * found to differentiate between the models upfront, so we enable
183 + * the quirk in response to seeing a button press in the trackstick
184 + * packet.
185 + */
186 + left = packet[3] & 0x01;
187 + right = packet[3] & 0x02;
188 + middle = packet[3] & 0x04;
189 +
190 + if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) &&
191 + (left || right || middle))
192 + priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS;
193 +
194 + if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) {
195 + input_report_key(dev, BTN_LEFT, left);
196 + input_report_key(dev, BTN_RIGHT, right);
197 + input_report_key(dev, BTN_MIDDLE, middle);
198 + }
199 +
200 + input_sync(dev);
201 + return;
202 +}
203 +
204 +static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
205 +{
206 + struct alps_data *priv = psmouse->private;
207 + unsigned char *packet = psmouse->packet;
208 + struct input_dev *dev = psmouse->dev;
209 + struct input_dev *dev2 = priv->dev2;
210 + int x, y, z;
211 + int left, right, middle;
212 +
213 + /*
214 + * There's no single feature of touchpad position and bitmap
215 + * packets that can be used to distinguish between them. We
216 + * rely on the fact that a bitmap packet should always follow
217 + * a position packet with bit 6 of packet[4] set.
218 + */
219 + if (priv->multi_packet) {
220 + priv->multi_packet = 0;
221 +
222 + /*
223 + * Sometimes a position packet will indicate a multi-packet
224 + * sequence, but then what follows is another position
225 + * packet. Check for this, and when it happens process the
226 + * position packet as usual.
227 + */
228 + if (packet[0] & 0x40) {
229 + /*
230 + * Bitmap packets are not yet supported, so for now
231 + * just ignore them.
232 + */
233 + return;
234 + }
235 + }
236 +
237 + if (!priv->multi_packet && (packet[4] & 0x40))
238 + priv->multi_packet = 1;
239 + else
240 + priv->multi_packet = 0;
241 +
242 + left = packet[3] & 0x01;
243 + right = packet[3] & 0x02;
244 + middle = packet[3] & 0x04;
245 +
246 + x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) |
247 + ((packet[0] & 0x30) >> 4);
248 + y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f);
249 + z = packet[5] & 0x7f;
250 +
251 + /*
252 + * Sometimes the hardware sends a single packet with z = 0
253 + * in the middle of a stream. Real releases generate packets
254 + * with x, y, and z all zero, so these seem to be flukes.
255 + * Ignore them.
256 + */
257 + if (x && y && !z)
258 + return;
259 +
260 + if (z >= 64) {
261 + input_report_key(dev, BTN_TOUCH, 1);
262 + } else {
263 + input_report_key(dev, BTN_TOUCH, 0);
264 + }
265 +
266 + if (z > 0) {
267 + input_report_abs(dev, ABS_X, x);
268 + input_report_abs(dev, ABS_Y, y);
269 + }
270 + input_report_abs(dev, ABS_PRESSURE, z);
271 +
272 + input_report_key(dev, BTN_TOOL_FINGER, z > 0);
273 + input_report_key(dev, BTN_LEFT, left);
274 + input_report_key(dev, BTN_RIGHT, right);
275 + input_report_key(dev, BTN_MIDDLE, middle);
276 +
277 + input_sync(dev);
278 +
279 + if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
280 + left = packet[3] & 0x10;
281 + right = packet[3] & 0x20;
282 + middle = packet[3] & 0x40;
283 +
284 + input_report_key(dev2, BTN_LEFT, left);
285 + input_report_key(dev2, BTN_RIGHT, right);
286 + input_report_key(dev2, BTN_MIDDLE, middle);
287 + input_sync(dev2);
288 + }
289 +}
290 +
291 +static void alps_process_packet_v3(struct psmouse *psmouse)
292 +{
293 + unsigned char *packet = psmouse->packet;
294 +
295 + /*
296 + * v3 protocol packets come in three types, two representing
297 + * touchpad data and one representing trackstick data.
298 + * Trackstick packets seem to be distinguished by always
299 + * having 0x3f in the last byte. This value has never been
300 + * observed in the last byte of either of the other types
301 + * of packets.
302 + */
303 + if (packet[5] == 0x3f) {
304 + alps_process_trackstick_packet_v3(psmouse);
305 + return;
306 + }
307 +
308 + alps_process_touchpad_packet_v3(psmouse);
309 +}
310 +
311 +static void alps_process_packet_v4(struct psmouse *psmouse)
312 +{
313 + unsigned char *packet = psmouse->packet;
314 + struct input_dev *dev = psmouse->dev;
315 + int x, y, z;
316 + int left, right;
317 +
318 + left = packet[4] & 0x01;
319 + right = packet[4] & 0x02;
320 +
321 + x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
322 + ((packet[0] & 0x30) >> 4);
323 + y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
324 + z = packet[5] & 0x7f;
325 +
326 + if (z >= 64) {
327 + input_report_key(dev, BTN_TOUCH, 1);
328 + } else {
329 + input_report_key(dev, BTN_TOUCH, 0);
330 + }
331 +
332 + if (z > 0) {
333 + input_report_abs(dev, ABS_X, x);
334 + input_report_abs(dev, ABS_Y, y);
335 + }
336 + input_report_abs(dev, ABS_PRESSURE, z);
337 +
338 + input_report_key(dev, BTN_TOOL_FINGER, z > 0);
339 + input_report_key(dev, BTN_LEFT, left);
340 + input_report_key(dev, BTN_RIGHT, right);
341 +
342 + input_sync(dev);
343 +}
344 +
345 +static void alps_process_packet(struct psmouse *psmouse)
346 +{
347 + struct alps_data *priv = psmouse->private;
348 + const struct alps_model_info *model = priv->i;
349 +
350 + switch (model->proto_version) {
351 + case ALPS_PROTO_V1:
352 + case ALPS_PROTO_V2:
353 + alps_process_packet_v1_v2(psmouse);
354 + break;
355 + case ALPS_PROTO_V3:
356 + alps_process_packet_v3(psmouse);
357 + break;
358 + case ALPS_PROTO_V4:
359 + alps_process_packet_v4(psmouse);
360 + break;
361 + }
362 +}
363 +
364 static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
365 unsigned char packet[],
366 bool report_buttons)
367 @@ -381,11 +648,126 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
368 return PSMOUSE_GOOD_DATA;
369 }
370
371 +static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble)
372 +{
373 + struct ps2dev *ps2dev = &psmouse->ps2dev;
374 + struct alps_data *priv = psmouse->private;
375 + int command;
376 + unsigned char *param;
377 + unsigned char dummy[4];
378 +
379 + BUG_ON(nibble > 0xf);
380 +
381 + command = priv->nibble_commands[nibble].command;
382 + param = (command & 0x0f00) ?
383 + dummy : (unsigned char *)&priv->nibble_commands[nibble].data;
384 +
385 + if (ps2_command(ps2dev, param, command))
386 + return -1;
387 +
388 + return 0;
389 +}
390 +
391 +static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr)
392 +{
393 + struct ps2dev *ps2dev = &psmouse->ps2dev;
394 + struct alps_data *priv = psmouse->private;
395 + int i, nibble;
396 +
397 + if (ps2_command(ps2dev, NULL, priv->addr_command))
398 + return -1;
399 +
400 + for (i = 12; i >= 0; i -= 4) {
401 + nibble = (addr >> i) & 0xf;
402 + if (alps_command_mode_send_nibble(psmouse, nibble))
403 + return -1;
404 + }
405 +
406 + return 0;
407 +}
408 +
409 +static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
410 +{
411 + struct ps2dev *ps2dev = &psmouse->ps2dev;
412 + unsigned char param[4];
413 +
414 + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
415 + return -1;
416 +
417 + /*
418 + * The address being read is returned in the first two bytes
419 + * of the result. Check that this address matches the expected
420 + * address.
421 + */
422 + if (addr != ((param[0] << 8) | param[1]))
423 + return -1;
424 +
425 + return param[2];
426 +}
427 +
428 +static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
429 +{
430 + if (alps_command_mode_set_addr(psmouse, addr))
431 + return -1;
432 + return __alps_command_mode_read_reg(psmouse, addr);
433 +}
434 +
435 +static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value)
436 +{
437 + if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf))
438 + return -1;
439 + if (alps_command_mode_send_nibble(psmouse, value & 0xf))
440 + return -1;
441 + return 0;
442 +}
443 +
444 +static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr,
445 + u8 value)
446 +{
447 + if (alps_command_mode_set_addr(psmouse, addr))
448 + return -1;
449 + return __alps_command_mode_write_reg(psmouse, value);
450 +}
451 +
452 +static int alps_enter_command_mode(struct psmouse *psmouse,
453 + unsigned char *resp)
454 +{
455 + unsigned char param[4];
456 + struct ps2dev *ps2dev = &psmouse->ps2dev;
457 +
458 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
459 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
460 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
461 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
462 + pr_err("alps.c: failed to enter command mode\n");
463 + return -1;
464 + }
465 +
466 + if (param[0] != 0x88 && param[1] != 0x07) {
467 + pr_debug("alps.c: unknown response while entering command mode: %2.2x %2.2x %2.2x\n",
468 + param[0], param[1], param[2]);
469 + return -1;
470 + }
471 +
472 + if (resp)
473 + *resp = param[2];
474 + return 0;
475 +}
476 +
477 +static inline int alps_exit_command_mode(struct psmouse *psmouse)
478 +{
479 + struct ps2dev *ps2dev = &psmouse->ps2dev;
480 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM))
481 + return -1;
482 + return 0;
483 +}
484 +
485 static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
486 {
487 struct ps2dev *ps2dev = &psmouse->ps2dev;
488 static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
489 unsigned char param[4];
490 + const struct alps_model_info *model = NULL;
491 int i;
492
493 /*
494 @@ -431,12 +813,38 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
495 *version = (param[0] << 8) | (param[1] << 4) | i;
496 }
497
498 - for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
499 + for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
500 if (!memcmp(param, alps_model_data[i].signature,
501 - sizeof(alps_model_data[i].signature)))
502 - return alps_model_data + i;
503 + sizeof(alps_model_data[i].signature))) {
504 + model = alps_model_data + i;
505 + break;
506 + }
507 + }
508 +
509 + if (model && model->proto_version > ALPS_PROTO_V2) {
510 + /*
511 + * Need to check command mode response to identify
512 + * model
513 + */
514 + model = NULL;
515 + if (alps_enter_command_mode(psmouse, param)) {
516 + pr_warn("alps.c: touchpad failed to enter command mode\n");
517 + } else {
518 + for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
519 + if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
520 + alps_model_data[i].command_mode_resp == param[0]) {
521 + model = alps_model_data + i;
522 + break;
523 + }
524 + }
525 + alps_exit_command_mode(psmouse);
526 +
527 + if (!model)
528 + pr_debug("alps.c: Unknown command mode response %2.2x\n", param[0]);
529 + }
530 + }
531
532 - return NULL;
533 + return model;
534 }
535
536 /*
537 @@ -444,7 +852,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
538 * subsequent commands. It looks like glidepad is behind stickpointer,
539 * I'd thought it would be other way around...
540 */
541 -static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
542 +static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable)
543 {
544 struct ps2dev *ps2dev = &psmouse->ps2dev;
545 int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
546 @@ -461,7 +869,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
547 return 0;
548 }
549
550 -static int alps_absolute_mode(struct psmouse *psmouse)
551 +static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
552 {
553 struct ps2dev *ps2dev = &psmouse->ps2dev;
554
555 @@ -540,13 +948,13 @@ static int alps_poll(struct psmouse *psmouse)
556 return -1;
557
558 if (priv->i->flags & ALPS_PASS)
559 - alps_passthrough_mode(psmouse, true);
560 + alps_passthrough_mode_v2(psmouse, true);
561
562 poll_failed = ps2_command(&psmouse->ps2dev, buf,
563 PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
564
565 if (priv->i->flags & ALPS_PASS)
566 - alps_passthrough_mode(psmouse, false);
567 + alps_passthrough_mode_v2(psmouse, false);
568
569 if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
570 goto out;
571 @@ -567,13 +975,13 @@ out:
572 return ret;
573 }
574
575 -static int alps_hw_init(struct psmouse *psmouse)
576 +static int alps_hw_init_v1_v2(struct psmouse *psmouse)
577 {
578 struct alps_data *priv = psmouse->private;
579 const struct alps_model_info *model = priv->i;
580
581 if ((model->flags & ALPS_PASS) &&
582 - alps_passthrough_mode(psmouse, true)) {
583 + alps_passthrough_mode_v2(psmouse, true)) {
584 return -1;
585 }
586
587 @@ -582,13 +990,13 @@ static int alps_hw_init(struct psmouse *psmouse)
588 return -1;
589 }
590
591 - if (alps_absolute_mode(psmouse)) {
592 + if (alps_absolute_mode_v1_v2(psmouse)) {
593 printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
594 return -1;
595 }
596
597 if ((model->flags & ALPS_PASS) &&
598 - alps_passthrough_mode(psmouse, false)) {
599 + alps_passthrough_mode_v2(psmouse, false)) {
600 return -1;
601 }
602
603 @@ -601,6 +1009,295 @@ static int alps_hw_init(struct psmouse *psmouse)
604 return 0;
605 }
606
607 +/*
608 + * Enable or disable passthrough mode to the trackstick. Must be in
609 + * command mode when calling this function.
610 + */
611 +static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable)
612 +{
613 + int reg_val;
614 +
615 + reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
616 + if (reg_val == -1)
617 + return -1;
618 +
619 + if (enable)
620 + reg_val |= 0x01;
621 + else
622 + reg_val &= ~0x01;
623 +
624 + if (__alps_command_mode_write_reg(psmouse, reg_val))
625 + return -1;
626 +
627 + return 0;
628 +}
629 +
630 +/* Must be in command mode when calling this function */
631 +static int alps_absolute_mode_v3(struct psmouse *psmouse)
632 +{
633 + int reg_val;
634 +
635 + reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
636 + if (reg_val == -1)
637 + return -1;
638 +
639 + reg_val |= 0x06;
640 + if (__alps_command_mode_write_reg(psmouse, reg_val))
641 + return -1;
642 +
643 + return 0;
644 +}
645 +
646 +static int alps_hw_init_v3(struct psmouse *psmouse)
647 +{
648 + struct alps_data *priv = psmouse->private;
649 + struct ps2dev *ps2dev = &psmouse->ps2dev;
650 + int reg_val;
651 + unsigned char param[4];
652 +
653 + priv->nibble_commands = alps_v3_nibble_commands;
654 + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
655 +
656 + if (alps_enter_command_mode(psmouse, NULL))
657 + goto error;
658 +
659 + /* Check for trackstick */
660 + reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
661 + if (reg_val == -1)
662 + goto error;
663 + if (reg_val & 0x80) {
664 + if (alps_passthrough_mode_v3(psmouse, true))
665 + goto error;
666 + if (alps_exit_command_mode(psmouse))
667 + goto error;
668 +
669 + /*
670 + * E7 report for the trackstick
671 + *
672 + * There have been reports of failures to seem to trace back
673 + * to the above trackstick check failing. When these occur
674 + * this E7 report fails, so when that happens we continue
675 + * with the assumption that there isn't a trackstick after
676 + * all.
677 + */
678 + param[0] = 0x64;
679 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
680 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
681 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
682 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
683 + pr_warn("alps.c: trackstick E7 report failed\n");
684 + } else {
685 + pr_debug("alps.c: trackstick E7 report: %2.2x %2.2x %2.2x\n",
686 + param[0], param[1], param[2]);
687 +
688 + /*
689 + * Not sure what this does, but it is absolutely
690 + * essential. Without it, the touchpad does not
691 + * work at all and the trackstick just emits normal
692 + * PS/2 packets.
693 + */
694 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
695 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
696 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
697 + alps_command_mode_send_nibble(psmouse, 0x9) ||
698 + alps_command_mode_send_nibble(psmouse, 0x4)) {
699 + pr_err("alps.c: Error sending magic E6 sequence\n");
700 + goto error_passthrough;
701 + }
702 + }
703 +
704 + if (alps_enter_command_mode(psmouse, NULL))
705 + goto error_passthrough;
706 + if (alps_passthrough_mode_v3(psmouse, false))
707 + goto error;
708 + }
709 +
710 + if (alps_absolute_mode_v3(psmouse)) {
711 + pr_err("alps.c: Failed to enter absolute mode\n");
712 + goto error;
713 + }
714 +
715 + reg_val = alps_command_mode_read_reg(psmouse, 0x0006);
716 + if (reg_val == -1)
717 + goto error;
718 + if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
719 + goto error;
720 +
721 + reg_val = alps_command_mode_read_reg(psmouse, 0x0007);
722 + if (reg_val == -1)
723 + goto error;
724 + if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
725 + goto error;
726 +
727 + if (alps_command_mode_read_reg(psmouse, 0x0144) == -1)
728 + goto error;
729 + if (__alps_command_mode_write_reg(psmouse, 0x04))
730 + goto error;
731 +
732 + if (alps_command_mode_read_reg(psmouse, 0x0159) == -1)
733 + goto error;
734 + if (__alps_command_mode_write_reg(psmouse, 0x03))
735 + goto error;
736 +
737 + if (alps_command_mode_read_reg(psmouse, 0x0163) == -1)
738 + goto error;
739 + if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03))
740 + goto error;
741 +
742 + if (alps_command_mode_read_reg(psmouse, 0x0162) == -1)
743 + goto error;
744 + if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
745 + goto error;
746 +
747 + /*
748 + * This ensures the trackstick packets are in the format
749 + * supported by this driver. If bit 1 isn't set the packet
750 + * format is different.
751 + */
752 + if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82))
753 + goto error;
754 +
755 + alps_exit_command_mode(psmouse);
756 +
757 + /* Set rate and enable data reporting */
758 + param[0] = 0x64;
759 + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
760 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
761 + pr_err("alps.c: Failed to enable data reporting\n");
762 + return -1;
763 + }
764 +
765 + return 0;
766 +
767 +error_passthrough:
768 + /* Something failed while in passthrough mode, so try to get out */
769 + if (!alps_enter_command_mode(psmouse, NULL))
770 + alps_passthrough_mode_v3(psmouse, false);
771 +error:
772 + /*
773 + * Leaving the touchpad in command mode will essentially render
774 + * it unusable until the machine reboots, so exit it here just
775 + * to be safe
776 + */
777 + alps_exit_command_mode(psmouse);
778 + return -1;
779 +}
780 +
781 +/* Must be in command mode when calling this function */
782 +static int alps_absolute_mode_v4(struct psmouse *psmouse)
783 +{
784 + int reg_val;
785 +
786 + reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
787 + if (reg_val == -1)
788 + return -1;
789 +
790 + reg_val |= 0x02;
791 + if (__alps_command_mode_write_reg(psmouse, reg_val))
792 + return -1;
793 +
794 + return 0;
795 +}
796 +
797 +static int alps_hw_init_v4(struct psmouse *psmouse)
798 +{
799 + struct alps_data *priv = psmouse->private;
800 + struct ps2dev *ps2dev = &psmouse->ps2dev;
801 + unsigned char param[4];
802 +
803 + priv->nibble_commands = alps_v4_nibble_commands;
804 + priv->addr_command = PSMOUSE_CMD_DISABLE;
805 +
806 + if (alps_enter_command_mode(psmouse, NULL))
807 + goto error;
808 +
809 + if (alps_absolute_mode_v4(psmouse)) {
810 + pr_err("alps.c: Failed to enter absolute mode\n");
811 + goto error;
812 + }
813 +
814 + if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c))
815 + goto error;
816 +
817 + if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03))
818 + goto error;
819 +
820 + if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03))
821 + goto error;
822 +
823 + if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15))
824 + goto error;
825 +
826 + if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01))
827 + goto error;
828 +
829 + if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03))
830 + goto error;
831 +
832 + if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03))
833 + goto error;
834 +
835 + if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03))
836 + goto error;
837 +
838 + alps_exit_command_mode(psmouse);
839 +
840 + /*
841 + * This sequence changes the output from a 9-byte to an
842 + * 8-byte format. All the same data seems to be present,
843 + * just in a more compact format.
844 + */
845 + param[0] = 0xc8;
846 + param[1] = 0x64;
847 + param[2] = 0x50;
848 + if (ps2_command(ps2dev, &param[0], PSMOUSE_CMD_SETRATE) ||
849 + ps2_command(ps2dev, &param[1], PSMOUSE_CMD_SETRATE) ||
850 + ps2_command(ps2dev, &param[2], PSMOUSE_CMD_SETRATE) ||
851 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
852 + return -1;
853 +
854 + /* Set rate and enable data reporting */
855 + param[0] = 0x64;
856 + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
857 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
858 + pr_err("alps.c: Failed to enable data reporting\n");
859 + return -1;
860 + }
861 +
862 + return 0;
863 +
864 +error:
865 + /*
866 + * Leaving the touchpad in command mode will essentially render
867 + * it unusable until the machine reboots, so exit it here just
868 + * to be safe
869 + */
870 + alps_exit_command_mode(psmouse);
871 + return -1;
872 +}
873 +
874 +static int alps_hw_init(struct psmouse *psmouse)
875 +{
876 + struct alps_data *priv = psmouse->private;
877 + const struct alps_model_info *model = priv->i;
878 + int ret = -1;
879 +
880 + switch (model->proto_version) {
881 + case ALPS_PROTO_V1:
882 + case ALPS_PROTO_V2:
883 + ret = alps_hw_init_v1_v2(psmouse);
884 + break;
885 + case ALPS_PROTO_V3:
886 + ret = alps_hw_init_v3(psmouse);
887 + break;
888 + case ALPS_PROTO_V4:
889 + ret = alps_hw_init_v4(psmouse);
890 + break;
891 + }
892 +
893 + return ret;
894 +}
895 +
896 static int alps_reconnect(struct psmouse *psmouse)
897 {
898 const struct alps_model_info *model;
899 @@ -641,6 +1338,8 @@ int alps_init(struct psmouse *psmouse)
900
901 psmouse->private = priv;
902
903 + psmouse_reset(psmouse);
904 +
905 model = alps_get_model(psmouse, &version);
906 if (!model)
907 goto init_fail;
908 @@ -668,8 +1367,20 @@ int alps_init(struct psmouse *psmouse)
909 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
910
911 dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
912 - input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
913 - input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
914 +
915 + switch (model->proto_version) {
916 + case ALPS_PROTO_V1:
917 + case ALPS_PROTO_V2:
918 + input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
919 + input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
920 + break;
921 + case ALPS_PROTO_V3:
922 + case ALPS_PROTO_V4:
923 + input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0);
924 + input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0);
925 + break;
926 + }
927 +
928 input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
929
930 if (model->flags & ALPS_WHEEL) {
931 @@ -712,7 +1423,7 @@ int alps_init(struct psmouse *psmouse)
932 psmouse->poll = alps_poll;
933 psmouse->disconnect = alps_disconnect;
934 psmouse->reconnect = alps_reconnect;
935 - psmouse->pktsize = 6;
936 + psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6;
937
938 /* We are having trouble resyncing ALPS touchpads so disable it for now */
939 psmouse->resync_time = 0;
940 diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
941 index 4ce9bba..62db7f4 100644
942 --- a/drivers/input/mouse/alps.h
943 +++ b/drivers/input/mouse/alps.h
944 @@ -14,22 +14,36 @@
945
946 #define ALPS_PROTO_V1 0
947 #define ALPS_PROTO_V2 1
948 +#define ALPS_PROTO_V3 2
949 +#define ALPS_PROTO_V4 3
950
951 struct alps_model_info {
952 unsigned char signature[3];
953 + unsigned char command_mode_resp; /* v3/v4 only */
954 unsigned char proto_version;
955 unsigned char byte0, mask0;
956 unsigned char flags;
957 };
958
959 +struct alps_nibble_commands {
960 + int command;
961 + unsigned char data;
962 +};
963 +
964 struct alps_data {
965 struct input_dev *dev2; /* Relative device */
966 char phys[32]; /* Phys */
967 const struct alps_model_info *i;/* Info */
968 + const struct alps_nibble_commands *nibble_commands;
969 + int addr_command; /* Command to set register address */
970 int prev_fin; /* Finger bit from previous packet */
971 + int multi_packet; /* Multi-packet data in progress */
972 + u8 quirks;
973 struct timer_list timer;
974 };
975
976 +#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
977 +
978 #ifdef CONFIG_MOUSE_PS2_ALPS
979 int alps_detect(struct psmouse *psmouse, bool set_properties);
980 int alps_init(struct psmouse *psmouse);
981 --
982 1.7.4.1

  ViewVC Help
Powered by ViewVC 1.1.20