/[linux-patches]/genpatches-2.6/tags/3.0-30/2630_Input-ALPS-Add-semi-MT-support-for-v3-protocol.patch
Gentoo

Contents of /genpatches-2.6/tags/3.0-30/2630_Input-ALPS-Add-semi-MT-support-for-v3-protocol.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2206 - (show annotations) (download)
Mon Sep 17 18:58:14 2012 UTC (23 months, 4 weeks ago) by mpagano
File size: 10068 byte(s)
3.0-30 release
1 From 38f8cccfb3e7215f4c44b9526974a5f8dc36e438 Mon Sep 17 00:00:00 2001
2 From: Seth Forshee <seth.forshee@canonical.com>
3 Date: Thu, 15 Sep 2011 16:50:09 -0500
4 Subject: [PATCH 6/8] Input: ALPS - Add semi-MT support for v3 protocol
5
6 Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
7 ---
8 drivers/input/mouse/alps.c | 233 ++++++++++++++++++++++++++++++++++++++++----
9 drivers/input/mouse/alps.h | 1 +
10 2 files changed, 215 insertions(+), 19 deletions(-)
11
12 diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
13 index 8419c14..8902a11 100644
14 --- a/drivers/input/mouse/alps.c
15 +++ b/drivers/input/mouse/alps.c
16 @@ -17,6 +17,7 @@
17
18 #include <linux/slab.h>
19 #include <linux/input.h>
20 +#include <linux/input/mt.h>
21 #include <linux/serio.h>
22 #include <linux/libps2.h>
23
24 @@ -33,6 +34,12 @@
25 /*
26 * Definitions for ALPS version 3 and 4 command mode protocol
27 */
28 +#define ALPS_V3_X_MAX 2000
29 +#define ALPS_V3_Y_MAX 1400
30 +
31 +#define ALPS_BITMAP_X_BITS 15
32 +#define ALPS_BITMAP_Y_BITS 11
33 +
34 #define ALPS_CMD_NIBBLE_10 0x01f2
35
36 static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
37 @@ -257,6 +264,137 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
38 input_sync(dev);
39 }
40
41 +/*
42 + * Process bitmap data from v3 and v4 protocols. Returns the number of
43 + * fingers detected. A return value of 0 means at least one of the
44 + * bitmaps was empty.
45 + *
46 + * The bitmaps don't have enough data to track fingers, so this function
47 + * only generates points representing a bounding box of all contacts.
48 + * These points are returned in x1, y1, x2, and y2 when the return value
49 + * is greater than 0.
50 + */
51 +static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
52 + int *x1, int *y1, int *x2, int *y2)
53 +{
54 + struct alps_bitmap_point {
55 + int start_bit;
56 + int num_bits;
57 + };
58 +
59 + int fingers_x = 0, fingers_y = 0, fingers;
60 + int i, bit, prev_bit;
61 + struct alps_bitmap_point x_low = {0,}, x_high = {0,};
62 + struct alps_bitmap_point y_low = {0,}, y_high = {0,};
63 + struct alps_bitmap_point *point;
64 +
65 + if (!x_map || !y_map)
66 + return 0;
67 +
68 + *x1 = *y1 = *x2 = *y2 = 0;
69 +
70 + prev_bit = 0;
71 + point = &x_low;
72 + for (i = 0; x_map != 0; i++, x_map >>= 1) {
73 + bit = x_map & 1;
74 + if (bit) {
75 + if (!prev_bit) {
76 + point->start_bit = i;
77 + fingers_x++;
78 + }
79 + point->num_bits++;
80 + } else {
81 + if (prev_bit)
82 + point = &x_high;
83 + else
84 + point->num_bits = 0;
85 + }
86 + prev_bit = bit;
87 + }
88 +
89 + /*
90 + * y bitmap is reversed for what we need (lower positions are in
91 + * higher bits), so we process from the top end.
92 + */
93 + y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS);
94 + prev_bit = 0;
95 + point = &y_low;
96 + for (i = 0; y_map != 0; i++, y_map <<= 1) {
97 + bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
98 + if (bit) {
99 + if (!prev_bit) {
100 + point->start_bit = i;
101 + fingers_y++;
102 + }
103 + point->num_bits++;
104 + } else {
105 + if (prev_bit)
106 + point = &y_high;
107 + else
108 + point->num_bits = 0;
109 + }
110 + prev_bit = bit;
111 + }
112 +
113 + /*
114 + * Fingers can overlap, so we use the maximum count of fingers
115 + * on either axis as the finger count.
116 + */
117 + fingers = max(fingers_x, fingers_y);
118 +
119 + /*
120 + * If total fingers is > 1 but either axis reports only a single
121 + * contact, we have overlapping or adjacent fingers. For the
122 + * purposes of creating a bounding box, divide the single contact
123 + * (roughly) equally between the two points.
124 + */
125 + if (fingers > 1) {
126 + if (fingers_x == 1) {
127 + i = x_low.num_bits / 2;
128 + x_low.num_bits = x_low.num_bits - i;
129 + x_high.start_bit = x_low.start_bit + i;
130 + x_high.num_bits = max(i, 1);
131 + } else if (fingers_y == 1) {
132 + i = y_low.num_bits / 2;
133 + y_low.num_bits = y_low.num_bits - i;
134 + y_high.start_bit = y_low.start_bit + i;
135 + y_high.num_bits = max(i, 1);
136 + }
137 + }
138 +
139 + *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) /
140 + (2 * (ALPS_BITMAP_X_BITS - 1));
141 + *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) /
142 + (2 * (ALPS_BITMAP_Y_BITS - 1));
143 +
144 + if (fingers > 1) {
145 + *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) /
146 + (2 * (ALPS_BITMAP_X_BITS - 1));
147 + *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) /
148 + (2 * (ALPS_BITMAP_Y_BITS - 1));
149 + }
150 +
151 + return fingers;
152 +}
153 +
154 +static void alps_set_slot(struct input_dev *dev, int slot, bool active,
155 + int x, int y)
156 +{
157 + input_mt_slot(dev, slot);
158 + input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
159 + if (active) {
160 + input_report_abs(dev, ABS_MT_POSITION_X, x);
161 + input_report_abs(dev, ABS_MT_POSITION_Y, y);
162 + }
163 +}
164 +
165 +static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
166 + int x1, int y1, int x2, int y2)
167 +{
168 + alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
169 + alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
170 +}
171 +
172 static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
173 {
174 struct alps_data *priv = psmouse->private;
175 @@ -325,16 +463,17 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
176 struct input_dev *dev2 = priv->dev2;
177 int x, y, z;
178 int left, right, middle;
179 + int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
180 + int fingers = 0, bmap_fingers;
181 + unsigned int x_bitmap, y_bitmap;
182
183 /*
184 - * There's no single feature of touchpad position and bitmap
185 - * packets that can be used to distinguish between them. We
186 - * rely on the fact that a bitmap packet should always follow
187 - * a position packet with bit 6 of packet[4] set.
188 + * There's no single feature of touchpad position and bitmap packets
189 + * that can be used to distinguish between them. We rely on the fact
190 + * that a bitmap packet should always follow a position packet with
191 + * bit 6 of packet[4] set.
192 */
193 if (priv->multi_packet) {
194 - priv->multi_packet = 0;
195 -
196 /*
197 * Sometimes a position packet will indicate a multi-packet
198 * sequence, but then what follows is another position
199 @@ -342,18 +481,49 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
200 * position packet as usual.
201 */
202 if (packet[0] & 0x40) {
203 + fingers = (packet[5] & 0x3) + 1;
204 + x_bitmap = ((packet[4] & 0x7e) << 8) |
205 + ((packet[1] & 0x7f) << 2) |
206 + ((packet[0] & 0x30) >> 4);
207 + y_bitmap = ((packet[3] & 0x70) << 4) |
208 + ((packet[2] & 0x7f) << 1) |
209 + (packet[4] & 0x01);
210 +
211 + bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap,
212 + &x1, &y1, &x2, &y2);
213 +
214 /*
215 - * Bitmap packets are not yet supported, so for now
216 - * just ignore them.
217 + * We shouldn't report more than one finger if
218 + * we don't have two coordinates.
219 */
220 - return;
221 + if (fingers > 1 && bmap_fingers < 2)
222 + fingers = bmap_fingers;
223 +
224 + /* Now process position packet */
225 + packet = priv->multi_data;
226 + } else {
227 + priv->multi_packet = 0;
228 }
229 }
230
231 - if (!priv->multi_packet && (packet[4] & 0x40))
232 + /*
233 + * Bit 6 of byte 0 is not usually set in position packets. The only
234 + * times it seems to be set is in situations where the data is
235 + * suspect anyway, e.g. a palm resting flat on the touchpad. Given
236 + * this combined with the fact that this bit is useful for filtering
237 + * out misidentified bitmap packets, we reject anything with this
238 + * bit set.
239 + */
240 + if (packet[0] & 0x40)
241 + return;
242 +
243 + if (!priv->multi_packet && (packet[4] & 0x40)) {
244 priv->multi_packet = 1;
245 - else
246 - priv->multi_packet = 0;
247 + memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
248 + return;
249 + }
250 +
251 + priv->multi_packet = 0;
252
253 left = packet[3] & 0x01;
254 right = packet[3] & 0x02;
255 @@ -373,23 +543,39 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
256 if (x && y && !z)
257 return;
258
259 + /*
260 + * If we don't have MT data or the bitmaps were empty, we have
261 + * to rely on ST data.
262 + */
263 + if (!fingers) {
264 + x1 = x;
265 + y1 = y;
266 + fingers = z > 0 ? 1 : 0;
267 + }
268 +
269 if (z >= 64) {
270 input_report_key(dev, BTN_TOUCH, 1);
271 } else {
272 input_report_key(dev, BTN_TOUCH, 0);
273 }
274
275 + alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
276 +
277 + input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
278 + input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
279 + input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
280 + input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
281 +
282 + input_report_key(dev, BTN_LEFT, left);
283 + input_report_key(dev, BTN_RIGHT, right);
284 + input_report_key(dev, BTN_MIDDLE, middle);
285 +
286 if (z > 0) {
287 input_report_abs(dev, ABS_X, x);
288 input_report_abs(dev, ABS_Y, y);
289 }
290 input_report_abs(dev, ABS_PRESSURE, z);
291
292 - input_report_key(dev, BTN_TOOL_FINGER, z > 0);
293 - input_report_key(dev, BTN_LEFT, left);
294 - input_report_key(dev, BTN_RIGHT, right);
295 - input_report_key(dev, BTN_MIDDLE, middle);
296 -
297 input_sync(dev);
298
299 if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
300 @@ -1375,9 +1561,18 @@ int alps_init(struct psmouse *psmouse)
301 input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
302 break;
303 case ALPS_PROTO_V3:
304 + set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
305 + input_mt_init_slots(dev1, 2);
306 + input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
307 + input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
308 +
309 + set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
310 + set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
311 + set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
312 + /* fall through */
313 case ALPS_PROTO_V4:
314 - input_set_abs_params(dev1, ABS_X, 0, 2000, 0, 0);
315 - input_set_abs_params(dev1, ABS_Y, 0, 1400, 0, 0);
316 + input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
317 + input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
318 break;
319 }
320
321 diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
322 index 62db7f4..a00a4ab 100644
323 --- a/drivers/input/mouse/alps.h
324 +++ b/drivers/input/mouse/alps.h
325 @@ -38,6 +38,7 @@ struct alps_data {
326 int addr_command; /* Command to set register address */
327 int prev_fin; /* Finger bit from previous packet */
328 int multi_packet; /* Multi-packet data in progress */
329 + unsigned char multi_data[6]; /* Saved multi-packet data */
330 u8 quirks;
331 struct timer_list timer;
332 };
333 --
334 1.7.4.1

  ViewVC Help
Powered by ViewVC 1.1.20