/[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 2038 - (hide annotations) (download)
Wed Dec 28 14:41:46 2011 UTC (6 years, 8 months ago) by psomas
File size: 30460 byte(s)
3.0-14 release
1 mpagano 1989 From 0d2064f77fc5b1d983a0b6bf39b08c36d7b58d68 Mon Sep 17 00:00:00 2001
2 mpagano 1982 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 mpagano 1989 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 mpagano 1982 ---
16 mpagano 1989 drivers/input/mouse/alps.c | 787 +++++++++++++++++++++++++++++++++++++++++---
17 mpagano 1984 drivers/input/mouse/alps.h | 14 +
18 mpagano 1989 2 files changed, 763 insertions(+), 38 deletions(-)
19 mpagano 1982
20     diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
21 mpagano 1989 index 14d1f64..8419c14 100644
22 mpagano 1982 --- 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 mpagano 1984 + { { 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 mpagano 1982 };
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 mpagano 1989 @@ -210,6 +257,226 @@ static void alps_process_packet(struct psmouse *psmouse)
141 mpagano 1982 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 mpagano 1989 + /*
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 mpagano 1984 + 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 mpagano 1982 + 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 mpagano 1984 + struct input_dev *dev2 = priv->dev2;
210 mpagano 1982 + 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 mpagano 1984 + left = packet[3] & 0x01;
243     + right = packet[3] & 0x02;
244     + middle = packet[3] & 0x04;
245 mpagano 1982 +
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 mpagano 1989 + /*
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 mpagano 1982 + 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 mpagano 1984 +
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 mpagano 1982 +}
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 mpagano 1989 @@ -381,11 +648,126 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
368 mpagano 1982 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 mpagano 1989 @@ -431,12 +813,38 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
495 mpagano 1982 *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 mpagano 1989 +
509 mpagano 1982 + 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 mpagano 1989
532     - return NULL;
533 mpagano 1982 + return model;
534     }
535    
536     /*
537 mpagano 1989 @@ -444,7 +852,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
538 mpagano 1982 * 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 mpagano 1989 @@ -461,7 +869,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
547 mpagano 1982 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 mpagano 1989 @@ -540,13 +948,13 @@ static int alps_poll(struct psmouse *psmouse)
556 mpagano 1982 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 mpagano 1989 @@ -567,13 +975,13 @@ out:
572 mpagano 1982 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 mpagano 1989 @@ -582,13 +990,13 @@ static int alps_hw_init(struct psmouse *psmouse)
588 mpagano 1982 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 mpagano 1989 @@ -601,6 +1009,295 @@ static int alps_hw_init(struct psmouse *psmouse)
604 mpagano 1982 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 mpagano 1984 +
688     + /*
689 mpagano 1982 + * 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 mpagano 1989 @@ -641,6 +1338,8 @@ int alps_init(struct psmouse *psmouse)
900 mpagano 1982
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 mpagano 1989 @@ -668,8 +1367,20 @@ int alps_init(struct psmouse *psmouse)
909 mpagano 1982 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 mpagano 1989 @@ -712,7 +1423,7 @@ int alps_init(struct psmouse *psmouse)
932 mpagano 1982 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 mpagano 1984 index 4ce9bba..62db7f4 100644
942 mpagano 1982 --- a/drivers/input/mouse/alps.h
943     +++ b/drivers/input/mouse/alps.h
944 mpagano 1984 @@ -14,22 +14,36 @@
945 mpagano 1982
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 mpagano 1984 + u8 quirks;
973 mpagano 1982 struct timer_list timer;
974     };
975    
976 mpagano 1984 +#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 mpagano 1982 --
982     1.7.4.1
983    

  ViewVC Help
Powered by ViewVC 1.1.20