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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20