/[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 1982 - (hide annotations) (download)
Wed Sep 28 14:30:19 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: 29238 byte(s)
Adding ALPS patches for new touchpads from Seth Forshee at Ubuntu
1 mpagano 1982 From baf5955491da6d651054b32b7e43850a49c9c116 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 | 761 +++++++++++++++++++++++++++++++++++++++++---
9     drivers/input/mouse/alps.h | 11 +
10     2 files changed, 734 insertions(+), 38 deletions(-)
11    
12     diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
13     index 14d1f64..2615b92 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 }, /* Ahtec Laptop */
118     + { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT }, /* Ahtec Laptop */
119     + { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 }, /* Ahtec Laptop */
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,200 @@ 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     + left = packet[3] & 0x01;
161     + right = packet[3] & 0x02;
162     + middle = packet[3] & 0x04;
163     +
164     + /*
165     + * The x and y values tend to be quite large, and when used
166     + * alone the trackstick is difficult to use. Scale them down
167     + * to compensate.
168     + */
169     + x /= 8;
170     + y /= 8;
171     +
172     + input_report_rel(dev, REL_X, x);
173     + input_report_rel(dev, REL_Y, -y);
174     +
175     + input_report_key(dev, BTN_LEFT, left);
176     + input_report_key(dev, BTN_RIGHT, right);
177     + input_report_key(dev, BTN_MIDDLE, middle);
178     +
179     + input_sync(dev);
180     + return;
181     +}
182     +
183     +static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
184     +{
185     + struct alps_data *priv = psmouse->private;
186     + unsigned char *packet = psmouse->packet;
187     + struct input_dev *dev = psmouse->dev;
188     + int x, y, z;
189     + int left, right, middle;
190     +
191     + /*
192     + * There's no single feature of touchpad position and bitmap
193     + * packets that can be used to distinguish between them. We
194     + * rely on the fact that a bitmap packet should always follow
195     + * a position packet with bit 6 of packet[4] set.
196     + */
197     + if (priv->multi_packet) {
198     + priv->multi_packet = 0;
199     +
200     + /*
201     + * Sometimes a position packet will indicate a multi-packet
202     + * sequence, but then what follows is another position
203     + * packet. Check for this, and when it happens process the
204     + * position packet as usual.
205     + */
206     + if (packet[0] & 0x40) {
207     + /*
208     + * Bitmap packets are not yet supported, so for now
209     + * just ignore them.
210     + */
211     + return;
212     + }
213     + }
214     +
215     + if (!priv->multi_packet && (packet[4] & 0x40))
216     + priv->multi_packet = 1;
217     + else
218     + priv->multi_packet = 0;
219     +
220     + /*
221     + * Bits in the upper nibble of byte 3 represent the trackstick
222     + * buttons on some models, but on other models the trackstick
223     + * buttons are reported in the trackstic packets. If we try to
224     + * report the buttons on the trackstick device from here it can
225     + * lead to conflicts, so we treat any buttons reported in the
226     + * touchpad packets as belonging to the touchpad.
227     + */
228     + left = packet[3] & 0x11;
229     + right = packet[3] & 0x22;
230     + middle = packet[3] & 0x44;
231     +
232     + x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) |
233     + ((packet[0] & 0x30) >> 4);
234     + y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f);
235     + z = packet[5] & 0x7f;
236     +
237     + if (z >= 64) {
238     + input_report_key(dev, BTN_TOUCH, 1);
239     + } else {
240     + input_report_key(dev, BTN_TOUCH, 0);
241     + }
242     +
243     + if (z > 0) {
244     + input_report_abs(dev, ABS_X, x);
245     + input_report_abs(dev, ABS_Y, y);
246     + }
247     + input_report_abs(dev, ABS_PRESSURE, z);
248     +
249     + input_report_key(dev, BTN_TOOL_FINGER, z > 0);
250     + input_report_key(dev, BTN_LEFT, left);
251     + input_report_key(dev, BTN_RIGHT, right);
252     + input_report_key(dev, BTN_MIDDLE, middle);
253     +
254     + input_sync(dev);
255     +}
256     +
257     +static void alps_process_packet_v3(struct psmouse *psmouse)
258     +{
259     + unsigned char *packet = psmouse->packet;
260     +
261     + /*
262     + * v3 protocol packets come in three types, two representing
263     + * touchpad data and one representing trackstick data.
264     + * Trackstick packets seem to be distinguished by always
265     + * having 0x3f in the last byte. This value has never been
266     + * observed in the last byte of either of the other types
267     + * of packets.
268     + */
269     + if (packet[5] == 0x3f) {
270     + alps_process_trackstick_packet_v3(psmouse);
271     + return;
272     + }
273     +
274     + alps_process_touchpad_packet_v3(psmouse);
275     +}
276     +
277     +static void alps_process_packet_v4(struct psmouse *psmouse)
278     +{
279     + unsigned char *packet = psmouse->packet;
280     + struct input_dev *dev = psmouse->dev;
281     + int x, y, z;
282     + int left, right;
283     +
284     + left = packet[4] & 0x01;
285     + right = packet[4] & 0x02;
286     +
287     + x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
288     + ((packet[0] & 0x30) >> 4);
289     + y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
290     + z = packet[5] & 0x7f;
291     +
292     + if (z >= 64) {
293     + input_report_key(dev, BTN_TOUCH, 1);
294     + } else {
295     + input_report_key(dev, BTN_TOUCH, 0);
296     + }
297     +
298     + if (z > 0) {
299     + input_report_abs(dev, ABS_X, x);
300     + input_report_abs(dev, ABS_Y, y);
301     + }
302     + input_report_abs(dev, ABS_PRESSURE, z);
303     +
304     + input_report_key(dev, BTN_TOOL_FINGER, z > 0);
305     + input_report_key(dev, BTN_LEFT, left);
306     + input_report_key(dev, BTN_RIGHT, right);
307     +
308     + input_sync(dev);
309     +}
310     +
311     +static void alps_process_packet(struct psmouse *psmouse)
312     +{
313     + struct alps_data *priv = psmouse->private;
314     + const struct alps_model_info *model = priv->i;
315     +
316     + switch (model->proto_version) {
317     + case ALPS_PROTO_V1:
318     + case ALPS_PROTO_V2:
319     + alps_process_packet_v1_v2(psmouse);
320     + break;
321     + case ALPS_PROTO_V3:
322     + alps_process_packet_v3(psmouse);
323     + break;
324     + case ALPS_PROTO_V4:
325     + alps_process_packet_v4(psmouse);
326     + break;
327     + }
328     +}
329     +
330     static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
331     unsigned char packet[],
332     bool report_buttons)
333     @@ -381,11 +622,126 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
334     return PSMOUSE_GOOD_DATA;
335     }
336    
337     +static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble)
338     +{
339     + struct ps2dev *ps2dev = &psmouse->ps2dev;
340     + struct alps_data *priv = psmouse->private;
341     + int command;
342     + unsigned char *param;
343     + unsigned char dummy[4];
344     +
345     + BUG_ON(nibble > 0xf);
346     +
347     + command = priv->nibble_commands[nibble].command;
348     + param = (command & 0x0f00) ?
349     + dummy : (unsigned char *)&priv->nibble_commands[nibble].data;
350     +
351     + if (ps2_command(ps2dev, param, command))
352     + return -1;
353     +
354     + return 0;
355     +}
356     +
357     +static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr)
358     +{
359     + struct ps2dev *ps2dev = &psmouse->ps2dev;
360     + struct alps_data *priv = psmouse->private;
361     + int i, nibble;
362     +
363     + if (ps2_command(ps2dev, NULL, priv->addr_command))
364     + return -1;
365     +
366     + for (i = 12; i >= 0; i -= 4) {
367     + nibble = (addr >> i) & 0xf;
368     + if (alps_command_mode_send_nibble(psmouse, nibble))
369     + return -1;
370     + }
371     +
372     + return 0;
373     +}
374     +
375     +static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
376     +{
377     + struct ps2dev *ps2dev = &psmouse->ps2dev;
378     + unsigned char param[4];
379     +
380     + if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
381     + return -1;
382     +
383     + /*
384     + * The address being read is returned in the first two bytes
385     + * of the result. Check that this address matches the expected
386     + * address.
387     + */
388     + if (addr != ((param[0] << 8) | param[1]))
389     + return -1;
390     +
391     + return param[2];
392     +}
393     +
394     +static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
395     +{
396     + if (alps_command_mode_set_addr(psmouse, addr))
397     + return -1;
398     + return __alps_command_mode_read_reg(psmouse, addr);
399     +}
400     +
401     +static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value)
402     +{
403     + if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf))
404     + return -1;
405     + if (alps_command_mode_send_nibble(psmouse, value & 0xf))
406     + return -1;
407     + return 0;
408     +}
409     +
410     +static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr,
411     + u8 value)
412     +{
413     + if (alps_command_mode_set_addr(psmouse, addr))
414     + return -1;
415     + return __alps_command_mode_write_reg(psmouse, value);
416     +}
417     +
418     +static int alps_enter_command_mode(struct psmouse *psmouse,
419     + unsigned char *resp)
420     +{
421     + unsigned char param[4];
422     + struct ps2dev *ps2dev = &psmouse->ps2dev;
423     +
424     + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
425     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
426     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
427     + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
428     + pr_err("alps.c: failed to enter command mode\n");
429     + return -1;
430     + }
431     +
432     + if (param[0] != 0x88 && param[1] != 0x07) {
433     + pr_debug("alps.c: unknown response while entering command mode: %2.2x %2.2x %2.2x\n",
434     + param[0], param[1], param[2]);
435     + return -1;
436     + }
437     +
438     + if (resp)
439     + *resp = param[2];
440     + return 0;
441     +}
442     +
443     +static inline int alps_exit_command_mode(struct psmouse *psmouse)
444     +{
445     + struct ps2dev *ps2dev = &psmouse->ps2dev;
446     + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM))
447     + return -1;
448     + return 0;
449     +}
450     +
451     static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
452     {
453     struct ps2dev *ps2dev = &psmouse->ps2dev;
454     static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
455     unsigned char param[4];
456     + const struct alps_model_info *model = NULL;
457     int i;
458    
459     /*
460     @@ -431,12 +787,38 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
461     *version = (param[0] << 8) | (param[1] << 4) | i;
462     }
463    
464     - for (i = 0; i < ARRAY_SIZE(alps_model_data); i++)
465     + for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
466     if (!memcmp(param, alps_model_data[i].signature,
467     - sizeof(alps_model_data[i].signature)))
468     - return alps_model_data + i;
469     + sizeof(alps_model_data[i].signature))) {
470     + model = alps_model_data + i;
471     + break;
472     + }
473     + }
474     +
475     + if (model && model->proto_version > ALPS_PROTO_V2) {
476     + /*
477     + * Need to check command mode response to identify
478     + * model
479     + */
480     + model = NULL;
481     + if (alps_enter_command_mode(psmouse, param)) {
482     + pr_warn("alps.c: touchpad failed to enter command mode\n");
483     + } else {
484     + for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
485     + if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
486     + alps_model_data[i].command_mode_resp == param[0]) {
487     + model = alps_model_data + i;
488     + break;
489     + }
490     + }
491     + alps_exit_command_mode(psmouse);
492     +
493     + if (!model)
494     + pr_debug("alps.c: Unknown command mode response %2.2x\n", param[0]);
495     + }
496     + }
497    
498     - return NULL;
499     + return model;
500     }
501    
502     /*
503     @@ -444,7 +826,7 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
504     * subsequent commands. It looks like glidepad is behind stickpointer,
505     * I'd thought it would be other way around...
506     */
507     -static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
508     +static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable)
509     {
510     struct ps2dev *ps2dev = &psmouse->ps2dev;
511     int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
512     @@ -461,7 +843,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, bool enable)
513     return 0;
514     }
515    
516     -static int alps_absolute_mode(struct psmouse *psmouse)
517     +static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
518     {
519     struct ps2dev *ps2dev = &psmouse->ps2dev;
520    
521     @@ -540,13 +922,13 @@ static int alps_poll(struct psmouse *psmouse)
522     return -1;
523    
524     if (priv->i->flags & ALPS_PASS)
525     - alps_passthrough_mode(psmouse, true);
526     + alps_passthrough_mode_v2(psmouse, true);
527    
528     poll_failed = ps2_command(&psmouse->ps2dev, buf,
529     PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
530    
531     if (priv->i->flags & ALPS_PASS)
532     - alps_passthrough_mode(psmouse, false);
533     + alps_passthrough_mode_v2(psmouse, false);
534    
535     if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
536     goto out;
537     @@ -567,13 +949,13 @@ out:
538     return ret;
539     }
540    
541     -static int alps_hw_init(struct psmouse *psmouse)
542     +static int alps_hw_init_v1_v2(struct psmouse *psmouse)
543     {
544     struct alps_data *priv = psmouse->private;
545     const struct alps_model_info *model = priv->i;
546    
547     if ((model->flags & ALPS_PASS) &&
548     - alps_passthrough_mode(psmouse, true)) {
549     + alps_passthrough_mode_v2(psmouse, true)) {
550     return -1;
551     }
552    
553     @@ -582,13 +964,13 @@ static int alps_hw_init(struct psmouse *psmouse)
554     return -1;
555     }
556    
557     - if (alps_absolute_mode(psmouse)) {
558     + if (alps_absolute_mode_v1_v2(psmouse)) {
559     printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
560     return -1;
561     }
562    
563     if ((model->flags & ALPS_PASS) &&
564     - alps_passthrough_mode(psmouse, false)) {
565     + alps_passthrough_mode_v2(psmouse, false)) {
566     return -1;
567     }
568    
569     @@ -601,6 +983,295 @@ static int alps_hw_init(struct psmouse *psmouse)
570     return 0;
571     }
572    
573     +/*
574     + * Enable or disable passthrough mode to the trackstick. Must be in
575     + * command mode when calling this function.
576     + */
577     +static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable)
578     +{
579     + int reg_val;
580     +
581     + reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
582     + if (reg_val == -1)
583     + return -1;
584     +
585     + if (enable)
586     + reg_val |= 0x01;
587     + else
588     + reg_val &= ~0x01;
589     +
590     + if (__alps_command_mode_write_reg(psmouse, reg_val))
591     + return -1;
592     +
593     + return 0;
594     +}
595     +
596     +/* Must be in command mode when calling this function */
597     +static int alps_absolute_mode_v3(struct psmouse *psmouse)
598     +{
599     + int reg_val;
600     +
601     + reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
602     + if (reg_val == -1)
603     + return -1;
604     +
605     + reg_val |= 0x06;
606     + if (__alps_command_mode_write_reg(psmouse, reg_val))
607     + return -1;
608     +
609     + return 0;
610     +}
611     +
612     +static int alps_hw_init_v3(struct psmouse *psmouse)
613     +{
614     + struct alps_data *priv = psmouse->private;
615     + struct ps2dev *ps2dev = &psmouse->ps2dev;
616     + int reg_val;
617     + unsigned char param[4];
618     +
619     + priv->nibble_commands = alps_v3_nibble_commands;
620     + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
621     +
622     + if (alps_enter_command_mode(psmouse, NULL))
623     + goto error;
624     +
625     + /* Check for trackstick */
626     + reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
627     + if (reg_val == -1)
628     + goto error;
629     + if (reg_val & 0x80) {
630     + if (alps_passthrough_mode_v3(psmouse, true))
631     + goto error;
632     + if (alps_exit_command_mode(psmouse))
633     + goto error;
634     +
635     + /*
636     + * E7 report for the trackstick
637     + *
638     + * There have been reports of failures to seem to trace back
639     + * to the above trackstick check failing. When these occur
640     + * this E7 report fails, so when that happens we continue
641     + * with the assumption that there isn't a trackstick after
642     + * all.
643     + */
644     + param[0] = 0x64;
645     + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
646     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
647     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
648     + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
649     + pr_warn("alps.c: trackstick E7 report failed\n");
650     + } else {
651     + pr_debug("alps.c: trackstick E7 report: %2.2x %2.2x %2.2x\n",
652     + param[0], param[1], param[2]);
653     +
654     + /*
655     + * Not sure what this does, but it is absolutely
656     + * essential. Without it, the touchpad does not
657     + * work at all and the trackstick just emits normal
658     + * PS/2 packets.
659     + */
660     + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
661     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
662     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
663     + alps_command_mode_send_nibble(psmouse, 0x9) ||
664     + alps_command_mode_send_nibble(psmouse, 0x4)) {
665     + pr_err("alps.c: Error sending magic E6 sequence\n");
666     + goto error_passthrough;
667     + }
668     + }
669     +
670     + if (alps_enter_command_mode(psmouse, NULL))
671     + goto error_passthrough;
672     + if (alps_passthrough_mode_v3(psmouse, false))
673     + goto error;
674     + }
675     +
676     + if (alps_absolute_mode_v3(psmouse)) {
677     + pr_err("alps.c: Failed to enter absolute mode\n");
678     + goto error;
679     + }
680     +
681     + reg_val = alps_command_mode_read_reg(psmouse, 0x0006);
682     + if (reg_val == -1)
683     + goto error;
684     + if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
685     + goto error;
686     +
687     + reg_val = alps_command_mode_read_reg(psmouse, 0x0007);
688     + if (reg_val == -1)
689     + goto error;
690     + if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
691     + goto error;
692     +
693     + if (alps_command_mode_read_reg(psmouse, 0x0144) == -1)
694     + goto error;
695     + if (__alps_command_mode_write_reg(psmouse, 0x04))
696     + goto error;
697     +
698     + if (alps_command_mode_read_reg(psmouse, 0x0159) == -1)
699     + goto error;
700     + if (__alps_command_mode_write_reg(psmouse, 0x03))
701     + goto error;
702     +
703     + if (alps_command_mode_read_reg(psmouse, 0x0163) == -1)
704     + goto error;
705     + if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03))
706     + goto error;
707     +
708     + if (alps_command_mode_read_reg(psmouse, 0x0162) == -1)
709     + goto error;
710     + if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
711     + goto error;
712     +
713     + /*
714     + * This ensures the trackstick packets are in the format
715     + * supported by this driver. If bit 1 isn't set the packet
716     + * format is different.
717     + */
718     + if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82))
719     + goto error;
720     +
721     + alps_exit_command_mode(psmouse);
722     +
723     + /* Set rate and enable data reporting */
724     + param[0] = 0x64;
725     + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
726     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
727     + pr_err("alps.c: Failed to enable data reporting\n");
728     + return -1;
729     + }
730     +
731     + return 0;
732     +
733     +error_passthrough:
734     + /* Something failed while in passthrough mode, so try to get out */
735     + if (!alps_enter_command_mode(psmouse, NULL))
736     + alps_passthrough_mode_v3(psmouse, false);
737     +error:
738     + /*
739     + * Leaving the touchpad in command mode will essentially render
740     + * it unusable until the machine reboots, so exit it here just
741     + * to be safe
742     + */
743     + alps_exit_command_mode(psmouse);
744     + return -1;
745     +}
746     +
747     +/* Must be in command mode when calling this function */
748     +static int alps_absolute_mode_v4(struct psmouse *psmouse)
749     +{
750     + int reg_val;
751     +
752     + reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
753     + if (reg_val == -1)
754     + return -1;
755     +
756     + reg_val |= 0x02;
757     + if (__alps_command_mode_write_reg(psmouse, reg_val))
758     + return -1;
759     +
760     + return 0;
761     +}
762     +
763     +static int alps_hw_init_v4(struct psmouse *psmouse)
764     +{
765     + struct alps_data *priv = psmouse->private;
766     + struct ps2dev *ps2dev = &psmouse->ps2dev;
767     + unsigned char param[4];
768     +
769     + priv->nibble_commands = alps_v4_nibble_commands;
770     + priv->addr_command = PSMOUSE_CMD_DISABLE;
771     +
772     + if (alps_enter_command_mode(psmouse, NULL))
773     + goto error;
774     +
775     + if (alps_absolute_mode_v4(psmouse)) {
776     + pr_err("alps.c: Failed to enter absolute mode\n");
777     + goto error;
778     + }
779     +
780     + if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c))
781     + goto error;
782     +
783     + if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03))
784     + goto error;
785     +
786     + if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03))
787     + goto error;
788     +
789     + if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15))
790     + goto error;
791     +
792     + if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01))
793     + goto error;
794     +
795     + if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03))
796     + goto error;
797     +
798     + if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03))
799     + goto error;
800     +
801     + if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03))
802     + goto error;
803     +
804     + alps_exit_command_mode(psmouse);
805     +
806     + /*
807     + * This sequence changes the output from a 9-byte to an
808     + * 8-byte format. All the same data seems to be present,
809     + * just in a more compact format.
810     + */
811     + param[0] = 0xc8;
812     + param[1] = 0x64;
813     + param[2] = 0x50;
814     + if (ps2_command(ps2dev, &param[0], PSMOUSE_CMD_SETRATE) ||
815     + ps2_command(ps2dev, &param[1], PSMOUSE_CMD_SETRATE) ||
816     + ps2_command(ps2dev, &param[2], PSMOUSE_CMD_SETRATE) ||
817     + ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
818     + return -1;
819     +
820     + /* Set rate and enable data reporting */
821     + param[0] = 0x64;
822     + if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
823     + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
824     + pr_err("alps.c: Failed to enable data reporting\n");
825     + return -1;
826     + }
827     +
828     + return 0;
829     +
830     +error:
831     + /*
832     + * Leaving the touchpad in command mode will essentially render
833     + * it unusable until the machine reboots, so exit it here just
834     + * to be safe
835     + */
836     + alps_exit_command_mode(psmouse);
837     + return -1;
838     +}
839     +
840     +static int alps_hw_init(struct psmouse *psmouse)
841     +{
842     + struct alps_data *priv = psmouse->private;
843     + const struct alps_model_info *model = priv->i;
844     + int ret = -1;
845     +
846     + switch (model->proto_version) {
847     + case ALPS_PROTO_V1:
848     + case ALPS_PROTO_V2:
849     + ret = alps_hw_init_v1_v2(psmouse);
850     + break;
851     + case ALPS_PROTO_V3:
852     + ret = alps_hw_init_v3(psmouse);
853     + break;
854     + case ALPS_PROTO_V4:
855     + ret = alps_hw_init_v4(psmouse);
856     + break;
857     + }
858     +
859     + return ret;
860     +}
861     +
862     static int alps_reconnect(struct psmouse *psmouse)
863     {
864     const struct alps_model_info *model;
865     @@ -641,6 +1312,8 @@ int alps_init(struct psmouse *psmouse)
866    
867     psmouse->private = priv;
868    
869     + psmouse_reset(psmouse);
870     +
871     model = alps_get_model(psmouse, &version);
872     if (!model)
873     goto init_fail;
874     @@ -668,8 +1341,20 @@ int alps_init(struct psmouse *psmouse)
875     BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
876    
877     dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
878     - input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
879     - input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
880     +
881     + switch (model->proto_version) {
882     + case ALPS_PROTO_V1:
883     + case ALPS_PROTO_V2:
884     + input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
885     + input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
886     + break;
887     + case ALPS_PROTO_V3:
888     + case ALPS_PROTO_V4:
889     + input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0);
890     + input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0);
891     + break;
892     + }
893     +
894     input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
895    
896     if (model->flags & ALPS_WHEEL) {
897     @@ -712,7 +1397,7 @@ int alps_init(struct psmouse *psmouse)
898     psmouse->poll = alps_poll;
899     psmouse->disconnect = alps_disconnect;
900     psmouse->reconnect = alps_reconnect;
901     - psmouse->pktsize = 6;
902     + psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6;
903    
904     /* We are having trouble resyncing ALPS touchpads so disable it for now */
905     psmouse->resync_time = 0;
906     diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
907     index 4ce9bba..0d911cf 100644
908     --- a/drivers/input/mouse/alps.h
909     +++ b/drivers/input/mouse/alps.h
910     @@ -14,19 +14,30 @@
911    
912     #define ALPS_PROTO_V1 0
913     #define ALPS_PROTO_V2 1
914     +#define ALPS_PROTO_V3 2
915     +#define ALPS_PROTO_V4 3
916    
917     struct alps_model_info {
918     unsigned char signature[3];
919     + unsigned char command_mode_resp; /* v3/v4 only */
920     unsigned char proto_version;
921     unsigned char byte0, mask0;
922     unsigned char flags;
923     };
924    
925     +struct alps_nibble_commands {
926     + int command;
927     + unsigned char data;
928     +};
929     +
930     struct alps_data {
931     struct input_dev *dev2; /* Relative device */
932     char phys[32]; /* Phys */
933     const struct alps_model_info *i;/* Info */
934     + const struct alps_nibble_commands *nibble_commands;
935     + int addr_command; /* Command to set register address */
936     int prev_fin; /* Finger bit from previous packet */
937     + int multi_packet; /* Multi-packet data in progress */
938     struct timer_list timer;
939     };
940    
941     --
942     1.7.4.1
943    

  ViewVC Help
Powered by ViewVC 1.1.20