Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: drivers/input/mouse/cypress_i2c.c

Issue 6626009: Add new i2c-based input mouse driver into input subsystem for Cypress trackpad devices. (Closed) Base URL: http://git.chromium.org/git/kernel-next.git@chromeos-2.6.37
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « drivers/input/mouse/Makefile ('k') | include/linux/cyapa.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Cypress APA touchpad with I2C interface
3 *
4 * Copyright (C) 2009 Compulab, Ltd.
5 * Dudley Du <dudl@cypress.com>
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
9 * more details.
10 */
11
12
13 #include <linux/module.h>
14 #include <linux/i2c.h>
15 #include <linux/irq.h>
16 #include <linux/interrupt.h>
17 #include <linux/input.h>
18 #include <linux/delay.h>
19 #include <linux/workqueue.h>
20 #include <linux/slab.h>
21 #include <linux/gpio.h>
22
23 #include <linux/cyapa.h>
24
25
26 /* Debug macro */
27 #define CYAPA_DBG 0
28 #if CYAPA_DBG
29 #define DBGPRINTK(x) printk x
30 #define DBG_CYAPA_READ_BLOCK_DATA
31 #else
32 #define DBGPRINTK(x)
33 #endif
34
35 #define CYAPA_USE_I2C_REG_WRITE_BLOCK 0
36
37 /* Cypress I2C APA trackpad driver version is defined as bellow:
38 ** CYAPA_MAJOR_VER.CYAPA_MINOR_VER.CYAPA_REVISIOIN_VER . */
39 #define CYAPA_MAJOR_VER 0
40 #define CYAPA_MINOR_VER 9
41 #define CYAPA_REVISIOIN_VER 4
42
43 #define CYAPA_FILTER_EMPTY_DATA 0x7FFFFFFF
44
45 /* macro definication for gestures. */
46 /* --------------------------------------------------------------- */
47 /* |- bit 7 - 5 -|- bit 4 -0 -| */
48 /* |------------------------------|----------------------------- | */
49 /* |- finger number -|- gesture id -| */
50 /* --------------------------------------------------------------- */
51 #define GESTURE_FINGERS(x) ((((x) & 0x07) << 5) & 0xE0)
52 #define GESTURE_INDEX(x) (((x) & 0x1F))
53 #define GESTURE_ID_CODE(finger, index) \
54 (GESTURE_FINGERS(finger) | GESTURE_INDEX(index))
55
56 #define GESTURE_NONE 0x00
57 /* 0-finger gestures. */
58 #define GESTURE_PALM_REJECTIOIN GESTURE_ID_CODE(0, 1)
59 /* 1-finger gestures. */
60 #define GESTURE_SINGLE_TAP GESTURE_ID_CODE(1, 0)
61 #define GESTURE_DOUBLE_TAP GESTURE_ID_CODE(1, 1)
62 /*
63 ** one finger click and hold for more than definitioin time,
64 ** then to do something.
65 */
66 #define GESTURE_TAP_AND_HOLD GESTURE_ID_CODE(1, 2)
67 #define GESTURE_EDGE_MOTION GESTURE_ID_CODE(1, 3)
68 #define GESTURE_FLICK GESTURE_ID_CODE(1, 4)
69 /* GESTURE_DRAG : double click and hold, then move for drag.*/
70 #define GESTURE_DRAG GESTURE_ID_CODE(1, 5)
71 /* Depending on PSOC user module, it will give four different ID when scroll.*/
72 #define GESTURE_SCROLL_UP GESTURE_ID_CODE(1, 6)
73 #define GESTURE_SCROLL_DOWN GESTURE_ID_CODE(1, 7)
74 #define GESTURE_SCROLL_LEFT GESTURE_ID_CODE(1, 8)
75 #define GESTURE_SCROLL_RIGHT GESTURE_ID_CODE(1, 9)
76
77 /* 2-finger gestures */
78 #define GESTURE_2F_ZOOM_IN GESTURE_ID_CODE(2, 0)
79 #define GESTURE_2F_ZOOM_OUT GESTURE_ID_CODE(2, 1)
80 #define GESTURE_2F_SCROLL_UP GESTURE_ID_CODE(2, 2)
81 #define GESTURE_2F_SCROLL_DOWN GESTURE_ID_CODE(2, 3)
82 #define GESTURE_2F_SCROLL_LEFT GESTURE_ID_CODE(2, 4)
83 #define GESTURE_2F_SCROLL_RIGHT GESTURE_ID_CODE(2, 5)
84 #define GESTURE_2F_ROTATE GESTURE_ID_CODE(2, 6)
85 #define GESTURE_2F_PINCH GESTURE_ID_CODE(2, 7)
86 /* Activates the Right Click action */
87 #define GESTURE_2F_TAP GESTURE_ID_CODE(2, 8)
88 /* Single-Finger click and hold while a second finger is moving for dragging. */
89 #define GESTURE_2F_DRAG GESTURE_ID_CODE(2, 9)
90 #define GESTURE_2F_FLICK GESTURE_ID_CODE(2, 10)
91
92 /* 3-finger gestures */
93 #define GESTURE_3F_FLICK GESTURE_ID_CODE(3, 0)
94
95 /* 4-finger gestures */
96 #define GESTURE_4F_FLICK GESTURE_ID_CODE(4, 0)
97
98 /* 5-finger gestures */
99 #define GESTURE_5F_FLICK GESTURE_ID_CODE(5, 0)
100
101 /* swith of the gesture, */
102 #define GESTURE_MULTI_TOUCH_ONE_CLICK 0
103
104 #define GESTURE_DECODE_FINGERS(x) (((x) >> 5) & 0x07)
105 #define GESTURE_DECODE_INDEX(x) ((x) & 0x1F)
106
107 /* max gesture index value for each fingers type is 31. 0~21.*/
108 #define MAX_FINGERS 5
109
110
111 /* parameter value for input_report_key(BTN_TOOL_WIDTH) */
112 #define CYAPA_TOOL_WIDTH 50
113
114 /* When in IRQ mode read the device every THREAD_IRQ_SLEEP_SECS */
115 #define CYAPA_THREAD_IRQ_SLEEP_SECS 2
116 #define CYAPA_THREAD_IRQ_SLEEP_MSECS \
117 (CYAPA_THREAD_IRQ_SLEEP_SECS * MSEC_PER_SEC)
118
119 /*
120 * When in Polling mode and no data received for CYAPA_NO_DATA_THRES msecs
121 * reduce the polling rate to CYAPA_NO_DATA_SLEEP_MSECS
122 */
123 #define CYAPA_NO_DATA_THRES (MSEC_PER_SEC)
124 #define CYAPA_NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4)
125
126 /* report data start reg offset address. */
127 #define DATA_REG_START_OFFSET 0x0000
128 /* relative data report data size. */
129 #define CYAPA_REL_REG_DATA_SIZE 5
130
131
132 /* Device Sleep Modes */
133 #define DEV_POWER_REG 0x0009
134 #define INTERRUPT_MODE_MASK 0x01
135 #define PWR_LEVEL_MASK 0x06
136 #define PWR_BITS_SHITF 1
137 #define GET_PWR_LEVEL(reg) \
138 ((((unsigned char)(reg))&PWR_LEVEL_MASK)>>PWR_BITS_SHITF)
139
140 /* protocol V1. */
141 #define REG_GESTURES 0x0B
142
143 /* definition to store platfrom data. */
144 static struct cyapa_platform_data cyapa_i2c_platform_data = {
145 .flag = 0,
146 .gen = CYAPA_GEN2,
147 .power_state = CYAPA_PWR_ACTIVE,
148 .use_absolute_mode = true,
149 .use_polling_mode = false,
150 .polling_interval_time_active = CYAPA_ACTIVE_POLLING_INTVAL_TIME,
151 .polling_interval_time_lowpower = CYAPA_LOWPOWER_POLLING_INTVAL_TIME,
152 .active_touch_timeout = CYAPA_ACTIVE_TOUCH_TIMEOUT,
153 .name = CYAPA_I2C_NAME,
154 .irq_gpio = -1,
155 .report_rate = CYAPA_REPORT_RATE,
156 };
157
158
159 /*
160 ** APA trackpad device states.
161 ** Used in register 0x00, bit1-0, DeviceStatus field.
162 */
163 enum cyapa_devicestate {
164 CYAPA_DEV_NORNAL = 0x03,
165 /*
166 ** After trackpad booted, and can report data, it should set this value.
167 ** 0ther values stand for trackpad device is in abnormal state.
168 ** maybe need to do reset operation to it.
169 ** Other values are defined later if needed.
170 */
171 };
172
173 #define CYAPA_MAX_TOUCHS (MAX_FINGERS)
174 /*
175 ** only 1 gesture can be reported one time right now.
176 */
177 #define CYAPA_ONE_TIME_GESTURES (1)
178 struct cyapa_touch_gen1 {
179 u8 rel_xy;
180 u8 rel_x;
181 u8 rel_y;
182 };
183
184 struct cyapa_reg_data_gen1 {
185 u8 tap_motion;
186 s8 deltax;
187 s8 deltay;
188 u8 reserved1;
189 u8 reserved2;
190
191 struct cyapa_touch_gen1 touch1;
192 u8 touch_fingers;
193 u8 feature_config;
194 u8 avg_pressure; /* average of all touched fingers. */
195 u8 gesture_status;
196 struct cyapa_touch_gen1 touchs[CYAPA_MAX_TOUCHS-1];
197 };
198
199 struct cyapa_touch_gen2 {
200 u8 xy;
201 u8 x;
202 u8 y;
203 u8 id;
204 };
205
206 struct cyapa_gesture {
207 u8 id;
208 u8 param1;
209 u8 param2;
210 };
211
212 struct cyapa_reg_data_gen2 {
213 u8 device_status;
214 u8 relative_flags;
215 s8 deltax;
216 s8 deltay;
217 u8 avg_pressure;
218 u8 touch_fingers;
219 u8 reserved1;
220 u8 reserved2;
221 struct cyapa_touch_gen2 touchs[CYAPA_MAX_TOUCHS];
222 u8 gesture_count;
223 struct cyapa_gesture gesture[CYAPA_ONE_TIME_GESTURES];
224 };
225
226 union cyapa_reg_data {
227 struct cyapa_reg_data_gen1 gen1_data;
228 struct cyapa_reg_data_gen2 gen2_data;
229 };
230
231 struct cyapa_touch {
232 int x;
233 int y;
234 int id;
235 };
236
237 struct cyapa_report_data {
238 u8 button;
239 u8 reserved1;
240 u8 reserved2;
241 u8 avg_pressure;
242 int rel_deltaX;
243 int rel_deltaY;
244
245 int touch_fingers;
246 struct cyapa_touch touchs[CYAPA_MAX_TOUCHS];
247
248 /* in gen1 and gen2, only 1 gesture one time supported. */
249 int gestures_count;
250 struct cyapa_gesture gestures[CYAPA_ONE_TIME_GESTURES];
251 };
252
253 struct speed_preferences {
254 int default_threshold; /* small scroll speed threshold. */
255 int middle_threshold;
256 int fast_threshold;
257 };
258
259 struct mouse_ballistic_params {
260 /*
261 ** platfrom display aspect ratio adjustment parameters.
262 */
263 int abs_rise_y;
264 int abs_run_y;
265
266 /*
267 ** ABS FIR filter algorithm parameters.
268 */
269 int fir_abs_enabled;
270
271 int fir_abs_depth_max;
272 int fir_abs_depth_slew_count;
273
274 /* Eccentricity Limits. */
275 int fir_gentle_curve_eccentricity_max;
276 int fir_moderate_curve_eccentricity_max;
277
278 int fir_slow_speed_limit;
279 int fir_moderate_speed_limit;
280
281 int fir_gentle_curve_depth;
282 int fir_moderate_curve_depth;
283 int fir_slow_speed_depth;
284 int fir_moderate_speed_depth;
285
286 /*
287 ** ABS IIR filter algorithm parameters.
288 */
289 int iir_abs_enabled;
290 int iir_numerator;
291 int iir_denominator;
292
293 /*
294 ** REL motion speed/acceleration control filter algorithm parameters.
295 */
296 int rel_stroke_history_depth;
297
298 int rel_medium_speed_threshold;
299 int rel_fast_speed_threshold;
300 int rel_flick_speed_threshold;
301
302 int rel_motion_numerator;
303 int rel_medium_speed_numerator;
304 int rel_motion_denominator;
305
306 int rel_acceleration_numerator;
307 int rel_acceleration_denominator;
308
309 /*
310 ** REL IIR filter algorithm parameters.
311 */
312 int rel_iir_acceleration_numerator;
313 int rel_iir_acceleration_denominator;
314
315 int rel_max_acceleration_speed;
316 };
317
318 struct cyapa_preferences {
319 struct speed_preferences vscroll;
320 struct speed_preferences hscroll;
321 struct speed_preferences zoom;
322
323 struct mouse_ballistic_params mouse_ballistic;
324 };
325
326 enum fir_curve_mode {
327
328 FIR_CURVE_SLOW_SPEED_LINE = 0,
329 FIR_CURVE_MODERATE_SPEED_LINE = 1,
330 FIR_CURVE_FAST_SPEED_LINE = 2,
331 FIR_CURVE_GENTLE_CURVE = 3,
332 FIR_CURVE_MODERATE_CURVE = 4,
333 FIR_CURVE_FULL_STOP = 5,
334 FIR_CURVE_CIRCLE = 6,
335 FIR_CURVE_UNINITIALIZED = 0xFFFFFFFF
336 };
337
338 enum rel_stroke_speed {
339 REL_STROKE_SPEED_SLOW,
340 REL_STROKE_SPEED_MEDIUM,
341 REL_STROKE_SPEED_FAST,
342 REL_STROKE_SPEED_WARP
343 };
344
345 struct point {
346 int x;
347 int y;
348 };
349
350 /* MAX_FIR_DEPTH:
351 ** A macro defines the number of entries in the FIR FIFO. */
352 #define MAX_FIR_DEPTH 20
353 /* STROKE_HISTORY_RECS:
354 ** A macro which defines the number of samples stored
355 ** in the stroke history buffer. */
356 #define REL_STROKE_HISTORY_RECS 10
357 struct cyapa_cursor_filters {
358 enum fir_curve_mode fir_curve_type;
359
360 /* The cursor FIR filter FIFO for the X finger vector. */
361 int fir_vectors_x[MAX_FIR_DEPTH];
362 /* The cursor FIR filter FIFO for the Y finger vector. */
363 int fir_vectors_y[MAX_FIR_DEPTH];
364
365 /* The remnant from the previous X FIR averaging computation.
366 ** Re-scaled when FIR depth changes. */
367 int fir_x_mod;
368 /* The remnant from the previous Y FIR averaging computation.
369 ** Re-scaled when FIR depth changes. */
370 int fir_y_mod;
371
372 /* Current depth of the cursor FIR filter's 'X' FIFO. */
373 int fir_abs_depth_x;
374 /* Current depth of the cursor FIR filter's 'Y' FIFO. */
375 int fir_abs_depth_y;
376
377 /* Previous depth of the cursor FIR filter's 'X' FIFO.
378 ** Used to rescale modular residue when FIFO depth is dynamically
379 ** changed. */
380 int fir_abs_prev_depth_x;
381
382 /* Previous depth of the cursor FIR filter's 'Y' FIFO.
383 ** Used to rescale modular residue when FIFO depth is dynamically
384 */
385 int fir_abs_prev_depth_y;
386
387 /* Counter used to implement the cursor FIR X vector filter's slew rate.
388 ** The FIR filter's slew rate determines the speed at which the FIR
389 ** depth increases over time,
390 ** limited by cursor speed and arc severity. */
391 int fir_abs_depth_slew_counter_x;
392
393 /* Counter used to implement the cursor FIR Y vector filter's slew rate.
394 ** The FIR filter's slew rate determines the speed at which the FIR
395 ** depth increases over time,
396 ** limited by cursor speed and arc severity. */
397 int fir_abs_depth_slew_counter_y;
398
399 int fir_effective_max_depth;
400
401 /* The current state for one finger IIR filtering, X position. */
402 int iir_x;
403
404 /* The current state for one finger IIR filtering, Y position. */
405 int iir_y;
406
407 /* The modular remnant of the previous IIR division for
408 ** one finger X position IIR calculations. */
409 int iir_mod_x;
410
411 /* The modular remnant of the previous IIR division for
412 ** one finger Y position IIR calculations. */
413 int iir_mod_y;
414
415 struct point rel_stroke_history[REL_STROKE_HISTORY_RECS];
416 int rel_stroke_depth;
417 int rel_stroke_speed;
418
419 /* The running modular remainder from the Velocity X vector computation
420 ** the purpose of keeping the residue between report periods is to both
421 ** enhance precision and prevent uncontrolled 'losiness' of velocity. */
422 int rel_residue_x;
423
424 /* The running modular remainder from the Velocity Y vector computation
425 ** The purpose of keeping the residue between report periods is to both
426 ** enhance precision and prevent uncontrolled 'losiness' of velocity. */
427 int rel_residue_y;
428
429 /* The running modular remainder from the acceleration X vector
430 ** computation. */
431 int rel_prev_residue_accel_x;
432
433 /* The running modular remainder from the acceleration Y vector
434 ** computation. */
435 int rel_prev_residue_accel_y;
436
437 /* The running accelerated cursor motion IIR filter's X vector. */
438 int rel_prev_accel_iir_x;
439
440 /* The running accelerated cursor motion IIR filter's X vector's modular
441 ** residue. Prevents loss (slip) which would otherwise result from
442 ** the IIR computation. */
443 int rel_prev_accel_iir_mod_x;
444
445 /* The running accelerated cursor motion IIR filter's X vector. */
446 int rel_prev_accel_iir_y;
447
448 /* The running accelerated cursor motion IIR filter's X vector's modular
449 ** residue. Prevents loss (slip) which would otherwise result from
450 ** the IIR computation. */
451 int rel_prev_accel_iir_mod_y;
452 };
453
454 /* The main device structure */
455 struct cyapa_i2c {
456 struct i2c_client *client;
457 struct input_dev *input;
458 struct input_dev *input_wheel;
459 struct input_dev *input_kbd;
460 struct delayed_work dwork;
461 spinlock_t lock;
462 int no_data_count;
463 int scan_ms;
464 int read_pending;
465 int open_count;
466
467 int irq;
468 struct cyapa_platform_data *platform_data;
469 unsigned short data_base_offset;
470 unsigned short control_base_offset;
471 unsigned short command_base_offset;
472 unsigned short query_base_offset;
473
474 struct cyapa_preferences preferences;
475
476 int zoomin_delta;
477 int zoomout_delta;
478 int hscroll_left;
479 int hscroll_right;
480 int hscroll_canceled;
481 int delta_scroll_up;
482 int delta_scroll_down;
483 int delta_scroll_left;
484 int delta_scroll_right;
485 int zoom_trigged;
486
487 int abs_x;
488 int abs_y;
489 int prev_abs_x;
490 int prev_abs_y;
491 int rel_x;
492 int rel_y;
493 int prev_rel_x;
494 int prev_rel_y;
495 struct cyapa_cursor_filters cursor_filters;
496 unsigned char xy_touchs_included_bits;
497 unsigned char gesture_2F_drag_started;
498
499 unsigned long cur_active_gestures[MAX_FINGERS];
500 unsigned long prev_active_gestures[MAX_FINGERS];
501
502 int prev_touch_fingers;
503
504 /* read from query data region. */
505 char product_id[16];
506 unsigned char capability[14];
507 unsigned char fm_maj_ver; /* firmware major version. */
508 unsigned char fm_min_ver; /* firmware minor version. */
509 unsigned char hw_maj_ver; /* hardware major version. */
510 unsigned char hw_min_ver; /* hardware minor version. */
511 int max_absolution_x;
512 int max_absolution_y;
513 int physical_size_x;
514 int physical_size_y;
515 };
516
517
518 #ifdef DBG_CYAPA_READ_BLOCK_DATA
519 void cyapa_print_data_block(const char *func, u8 reg, u8 length, void *data)
520 {
521 char buf[512];
522 unsigned buf_len = sizeof(buf);
523 char *p = buf;
524 int i;
525 int l;
526
527 l = snprintf(p, buf_len, "reg 0x%04x: ", reg);
528 buf_len -= l;
529 p += l;
530 for (i = 0; i < length && buf_len; i++, p += l, buf_len -= l)
531 l = snprintf(p, buf_len, "%02x ", *((char *)data + i));
532 printk(KERN_INFO "%s: data block length = %d\n", func, length);
533 printk(KERN_INFO "%s: %s\n", func, buf);
534 }
535
536 void cyapa_print_report_data(const char *func,
537 struct cyapa_report_data *report_data)
538 {
539 int i;
540
541 printk(KERN_INFO "%s: ------------------------------------\n", func);
542 printk(KERN_INFO "%s: report_data.button = 0x%02x\n",
543 func, report_data->button);
544 printk(KERN_INFO "%s: report_data.avg_pressure = %d\n",
545 func, report_data->avg_pressure);
546 printk(KERN_INFO "%s: report_data.touch_fingers = %d\n",
547 func, report_data->touch_fingers);
548 for (i = 0; i < report_data->touch_fingers; i++) {
549 printk(KERN_INFO "%s: report_data.touchs[%d].x = %d\n",
550 func, i, report_data->touchs[i].x);
551 printk(KERN_INFO "%s: report_data.touchs[%d].y = %d\n",
552 func, i, report_data->touchs[i].y);
553 printk(KERN_INFO "%s: report_data.touchs[%d].id = %d\n",
554 func, i, report_data->touchs[i].id);
555 }
556 printk(KERN_INFO "%s: report_data.gestures_count = %d\n",
557 func, report_data->gestures_count);
558 for (i = 0; i < report_data->gestures_count; i++) {
559 printk(KERN_INFO "%s: report_data.gestures[%d].id = 0x%02x\n",
560 func, i, report_data->gestures[i].id);
561 printk(KERN_INFO "%s: report_data.gestures[%d].param1 = 0x%02x\n ",
562 func, i, report_data->gestures[i].param1);
563 printk(KERN_INFO "%s: report_data.gestures[%d].param2 = 0x%02x\n ",
564 func, i, report_data->gestures[i].param2);
565 }
566 printk(KERN_INFO "%s: -------------------------------------\n", func);
567 }
568
569 void cyapa_print_paltform_data(const char *func,
570 struct cyapa_platform_data *cyapa_i2c_platform_data)
571 {
572 printk(KERN_INFO "%s: -----------------------------------------\n",
573 func);
574 printk(KERN_INFO "%s: cyapa_i2c_platform_data.flag = 0x%08x\n",
575 func, cyapa_i2c_platform_data->flag);
576 printk(KERN_INFO "%s: cyapa_i2c_platform_data.gen = 0x%02x\n",
577 func, cyapa_i2c_platform_data->gen);
578 printk(KERN_INFO "%s: cyapa_i2c_platform_data.power_state = 0x%02x\n",
579 func, cyapa_i2c_platform_data->power_state);
580 printk(KERN_INFO "%s: cyapa_i2c_platform_data.use_absolute_mode = %s\n",
581 func,
582 cyapa_i2c_platform_data->use_absolute_mode ? "true" : "false");
583 printk(KERN_INFO "%s: cyapa_i2c_platform_data.use_polling_mode = %s\n",
584 func, cyapa_i2c_platform_data->use_polling_mode
585 ? "true" : "false");
586 printk(KERN_INFO "%s: cyapa_i2c_platform_data. \
587 polling_interval_time_active = %d\n",
588 func, cyapa_i2c_platform_data->polling_interval_time_active);
589 printk(KERN_INFO "%s: cyapa_i2c_platform_data \
590 .polling_interval_time_lowpower = %d\n",
591 func, cyapa_i2c_platform_data->polling_interval_time_lowpower);
592 printk(KERN_INFO "%s: cyapa_i2c_platform_data \
593 .active_touch_timeout = %d\n",
594 func, cyapa_i2c_platform_data->active_touch_timeout);
595 printk(KERN_INFO "%s: cyapa_i2c_platform_data.name = %s\n",
596 func, cyapa_i2c_platform_data->name);
597 printk(KERN_INFO "%s: cyapa_i2c_platform_data.irq_gpio = %d\n",
598 func, cyapa_i2c_platform_data->irq_gpio);
599 printk(KERN_INFO "%s: cyapa_i2c_platform_data.report_rate = %d\n",
600 func, cyapa_i2c_platform_data->report_rate);
601 printk(KERN_INFO "%s: cyapa_i2c_platform_data.init = %s%p\n",
602 func, cyapa_i2c_platform_data->init ? "0x" : "",
603 cyapa_i2c_platform_data->init);
604 printk(KERN_INFO "%s: cyapa_i2c_platform_data.wakeup = %s%p\n",
605 func, cyapa_i2c_platform_data->wakeup ? "0x" : "",
606 cyapa_i2c_platform_data->wakeup);
607 printk(KERN_INFO "%s: -----------------------------------------\n",
608 func);
609 }
610 #else
611 void cyapa_print_data_block(const char *func, u8 reg, u8 length, void *data) {}
612 void cyapa_print_report_data(const char *func,
613 struct cyapa_report_data *report_data) {}
614 void cyapa_print_paltform_data(const char *func,
615 struct cyapa_platform_data *cyapa_i2c_platform_data) {}
616 #endif
617
618
619 /*
620 * Driver's initial design makes no race condition possible on i2c bus,
621 * so there is no need in any locking.
622 * Keep it in mind, while playing with the code.
623 */
624 static s32 cyapa_i2c_reg_read_byte(struct i2c_client *client, u16 reg)
625 {
626 int ret;
627
628 ret = i2c_smbus_read_byte_data(client, (u8)reg & 0xff);
629
630 return ((ret < 0) ? 0 : ret);
631 }
632
633 static s32 cyapa_i2c_reg_write_byte(struct i2c_client *client, u16 reg, u8 val)
634 {
635 int ret;
636
637 ret = i2c_smbus_write_byte_data(client, (u8)reg & 0xff, val);
638
639 return ((ret < 0) ? 0 : ret);
640 }
641
642 static s32 cyapa_i2c_reg_read_block(struct i2c_client *client, u16 reg,
643 int length, u8 *values)
644 {
645 int retval;
646 u8 buf[1];
647
648 /*
649 ** depending on PSOC easy I2C read operations.
650 ** step1: set read pointer of easy I2C.
651 ** step2: read data.
652 */
653 /* step1: set read pointer of easy I2C. */
654 memset(buf, 0, 1);
655 buf[0] = (u8)(((u8)reg) & 0xff);
656 retval = i2c_master_send(client, buf, 1);
657 if (retval < 0) {
658 DBGPRINTK(("%s: i2c_master_send error, retval=%d\n",
659 __func__, retval));
660 return retval;
661 }
662
663 /* step2: read data. */
664 retval = i2c_master_recv(client, values, length);
665 if (retval < 0) {
666 DBGPRINTK(("%s: i2c_master_recv error, retval=%d\n",
667 __func__, retval));
668 return retval;
669 }
670
671 /* debug message */
672 cyapa_print_data_block(__func__, (u8)reg, retval, values);
673
674 if (retval != length) {
675 dev_warn(&client->dev,
676 "%s: warning I2C block read bytes \
677 [%d] not equal to required bytes [%d].\n",
678 __func__, retval, length);
679 }
680
681 return retval;
682 }
683
684 #if CYAPA_USE_I2C_REG_WRITE_BLOCK
685 static s32 cyapa_i2c_reg_write_block(struct i2c_client *client, u16 reg,
686 u8 length, const u8 *values)
687
688 {
689 int retval;
690 int i;
691 u8 buf[256];
692
693 if ((length+1) > 256) {
694 DBGPRINTK(("%s: invalid write data length, length=%d\n",
695 __func__, length));
696 return -EINVAL;
697 }
698
699 /*
700 ** depending on PSOC easy I2C read operations.
701 ** step1: write data to easy I2C in one command.
702 */
703 /* step1: write data to easy I2C in one command. */
704 memset(buf, 0, 256);
705 buf[0] = (u8)(((u8)reg) & 0xff);
706 /* move data shoud be write to I2C slave device. */
707 for (i = 1; i < length; i++)
708 buf[i] = values[i-1];
709
710 retval = i2c_master_send(client, buf, length+1);
711 if (retval < 0) {
712 DBGPRINTK(("%s: i2c_master_send error, retval=%d\n",
713 __func__, retval));
714 return retval;
715 }
716
717 if (retval != (length+1)) {
718 dev_warn(&client->dev,
719 "%s: warning I2C block write bytes \
720 [%d] not equal to required bytes [%d].\n",
721 __func__, retval, length);
722 }
723
724 return retval;
725 }
726 #endif
727
728 #define REG_OFFSET_DATA_BASE 0x0000
729 #define REG_OFFSET_CONTROL_BASE 0x0029
730 #define REG_OFFSET_COMMAND_BASE 0x0049
731 #define REG_OFFSET_QUERY_BASE 0x004B
732 static void cyapa_get_reg_offset(struct cyapa_i2c *touch)
733 {
734 touch->data_base_offset = REG_OFFSET_DATA_BASE;
735 touch->control_base_offset = REG_OFFSET_CONTROL_BASE;
736 touch->command_base_offset = REG_OFFSET_COMMAND_BASE;
737 touch->query_base_offset = REG_OFFSET_QUERY_BASE;
738
739 /* this function will be updated later depending firmware support. */
740 }
741
742 static void cyapa_get_query_data(struct cyapa_i2c *touch)
743 {
744 unsigned char query_data[40];
745 int ret_read_size = 0;
746 int i;
747
748 /* query data has been supported in GEN1 protocol.*/
749 if (touch->platform_data->gen == CYAPA_GEN2) {
750 memset(query_data, 0, 40);
751 ret_read_size = cyapa_i2c_reg_read_block(touch->client,
752 touch->query_base_offset,
753 38,
754 (u8 *)&query_data);
755
756 touch->product_id[0] = query_data[0];
757 touch->product_id[1] = query_data[1];
758 touch->product_id[2] = query_data[2];
759 touch->product_id[3] = query_data[3];
760 touch->product_id[4] = query_data[4];
761 touch->product_id[5] = '-';
762 touch->product_id[6] = query_data[5];
763 touch->product_id[7] = query_data[6];
764 touch->product_id[8] = query_data[7];
765 touch->product_id[9] = query_data[8];
766 touch->product_id[10] = query_data[9];
767 touch->product_id[11] = query_data[10];
768 touch->product_id[12] = '-';
769 touch->product_id[13] = query_data[11];
770 touch->product_id[14] = query_data[12];
771 touch->product_id[15] = '\0';
772
773 touch->fm_maj_ver = query_data[15];
774 touch->fm_min_ver = query_data[16];
775 touch->hw_maj_ver = query_data[17];
776 touch->hw_min_ver = query_data[18];
777
778 for (i = 0; i < 13; i++)
779 touch->capability[i] = query_data[19+i];
780
781 touch->max_absolution_x =
782 (((query_data[32] & 0xF0) << 4) | query_data[33]);
783 touch->max_absolution_y =
784 (((query_data[32] & 0x0F) << 8) | query_data[34]);
785 if (!touch->max_absolution_x || !touch->max_absolution_y) {
786 if (!strcmp(touch->product_id, "CYTRA-014001-00")) {
787 touch->max_absolution_x = 1600;
788 touch->max_absolution_y = 900;
789 } else {
790 touch->max_absolution_x = 1200;
791 touch->max_absolution_y = 600;
792 }
793 }
794
795 touch->physical_size_x =
796 (((query_data[35] & 0xF0) << 4) | query_data[36]);
797 touch->physical_size_y =
798 (((query_data[35] & 0x0F) << 8) | query_data[37]);
799 if (!touch->physical_size_x || !touch->physical_size_y) {
800 touch->physical_size_x = 105;
801 touch->physical_size_y = 60;
802 }
803
804 printk(KERN_INFO "Cypress Trackpad Information:\n");
805 printk(KERN_INFO "\t\t\tProduction ID: %s\n",
806 touch->product_id);
807 printk(KERN_INFO "\t\t\tFirmware version: %d.%d\n",
808 touch->fm_maj_ver, touch->fm_min_ver);
809 printk(KERN_INFO "\t\t\tHardware version: %d.%d\n",
810 touch->hw_maj_ver, touch->hw_min_ver);
811 printk(KERN_INFO "\t\t\tDriver Version: %d.%d.%d\n",
812 CYAPA_MAJOR_VER, CYAPA_MINOR_VER, CYAPA_REVISIOIN_VER);
813 printk(KERN_INFO "\t\t\tResolution X,Y: %d,%d\n",
814 touch->max_absolution_x, touch->max_absolution_y);
815 printk(KERN_INFO "\t\t\tPhysical Size X,Y: %d,%d\n",
816 touch->physical_size_x, touch->physical_size_y);
817 }
818 }
819
820 static int cyapa_i2c_reconfig(struct cyapa_i2c *touch)
821 {
822 struct i2c_client *client = touch->client;
823 int regval = 0;
824 int retval = 0;
825
826 if (touch->platform_data->gen == CYAPA_GEN1) {
827 /* trackpad gen1 firmware. */
828 DBGPRINTK(("%s: trackpad support gen1 firmware.\n", __func__));
829
830 regval = cyapa_i2c_reg_read_byte(client, DEV_POWER_REG);
831 DBGPRINTK(("%s: read trackpad interrupt bit = 0x%02x\n",
832 __func__, regval&INTERRUPT_MODE_MASK));
833
834 if ((touch->platform_data->use_polling_mode == true)
835 && ((regval & INTERRUPT_MODE_MASK)
836 == INTERRUPT_MODE_MASK)) {
837 /* reset trackpad to polling mode. */
838 regval &= (~INTERRUPT_MODE_MASK);
839 retval = cyapa_i2c_reg_write_byte(client, DEV_POWER_REG,
840 (u8)(regval & 0xff));
841 if (retval) {
842 DBGPRINTK(("%s: set to polliing mode failed,\
843 retval=%d.\n", __func__, retval));
844 /*
845 * Though firmware has set interrupt mode bit.
846 * but since platfrom doesn't support
847 * interrupt mode, so also use polling mode here
848 * do nothing.
849 */
850 }
851 } else if ((touch->platform_data->use_polling_mode == false)
852 && ((regval & INTERRUPT_MODE_MASK)
853 != INTERRUPT_MODE_MASK)) {
854 /* reset trackpad to interrupt mode. */
855 regval |= INTERRUPT_MODE_MASK;
856 retval = cyapa_i2c_reg_write_byte(client, DEV_POWER_REG,
857 (u8)(regval & 0xff));
858 if (retval) {
859 DBGPRINTK(("%s: set to interrup mode failed, \
860 retval=%d.\n", __func__, retval));
861 touch->platform_data->use_polling_mode = true;
862 }
863 }
864
865 DBGPRINTK(("%s: trackpad interrupt bit = 0x%02x\n", __func__,
866 (u8)cyapa_i2c_reg_read_byte(client, DEV_POWER_REG)));
867 } else {
868 /* trackpad gen2 firmware. default is interrupt mode. */
869 DBGPRINTK(("%s: trackpad support gen2 firmware.\n", __func__));
870
871 cyapa_get_reg_offset(touch);
872 cyapa_get_query_data(touch);
873 }
874
875 DBGPRINTK(("%s: use %s mode.\n", __func__,
876 ((touch->platform_data->use_polling_mode == true)
877 ? "polling" : "interrupt")));
878 return retval;
879 }
880
881 static int cyapa_i2c_reset_config(struct cyapa_i2c *touch)
882 {
883 int ret = 0;
884
885 DBGPRINTK(("%s: ...\n", __func__));
886
887 return ret;
888 }
889
890 static int cyapa_verify_data_device(struct cyapa_i2c *touch,
891 union cyapa_reg_data *reg_data)
892 {
893 struct cyapa_reg_data_gen1 *data_gen1 = NULL;
894 struct cyapa_reg_data_gen2 *data_gen2 = NULL;
895
896 if (touch->platform_data->gen == CYAPA_GEN1) {
897 data_gen1 = &reg_data->gen1_data;
898 if ((data_gen1->tap_motion & 0x08) != 0x08) {
899 /* invalid data. */
900 DBGPRINTK(("%s: invalid data reg address 0x00, \
901 bit3 is not set.\n", __func__));
902 return -EINVAL;
903 }
904 } else {
905 data_gen2 = &reg_data->gen2_data;
906 if ((data_gen2->device_status & 0x80) != 0x80) {
907 /* invalid data. */
908 DBGPRINTK(("%s: invalid data reg address 0x00, \
909 bit7 is not set.\n", __func__));
910 return -EINVAL;
911 }
912
913 if ((data_gen2->device_status & 0x03) != CYAPA_DEV_NORNAL) {
914 DBGPRINTK(("%s: invalid device status = 0x%02x, \
915 wait for device ready.\n",
916 __func__, (data_gen2->device_status & 0x03)));
917 return -EBUSY;
918 }
919 }
920
921 return 0;
922 }
923
924 static inline void cyapa_calculate_abs_xy(struct cyapa_i2c *touch,
925 struct cyapa_report_data *report_data)
926 {
927 int i;
928 int sum_x = 0, sum_y = 0;
929
930 /* invalid input data. */
931 if (!touch->xy_touchs_included_bits || !report_data->touch_fingers) {
932 touch->prev_abs_x = -1;
933 touch->prev_abs_y = -1;
934 return;
935 }
936
937 for (i = 0; i < CYAPA_MAX_TOUCHS; i++) {
938 if (touch->xy_touchs_included_bits & (0x01 << i)) {
939 sum_x += report_data->touchs[i].x;
940 sum_y += report_data->touchs[i].y;
941 }
942 }
943
944 touch->abs_x = sum_x / report_data->touch_fingers;
945 touch->abs_y = sum_y / report_data->touch_fingers;
946 /* x, y directory of Cypress trackpad is in negative direction of screen
947 ** for some platform it maybe different. */
948 /***
949 touch->abs_x = touch->platform_data->max_touchpad_x - touch->abs_x;
950 touch->abs_y = touch->platform_data->max_touchpad_y - touch->abs_y;
951 ***/
952
953 /* use simple filtr to make cursor move smoother. */
954 if (touch->prev_abs_x != -1) {
955 touch->abs_x = (touch->abs_x * 3 + touch->prev_abs_x) >> 2;
956 touch->abs_y = (touch->abs_y * 3 + touch->prev_abs_y) >> 2;
957 }
958
959 touch->prev_abs_x = touch->abs_x;
960 touch->prev_abs_y = touch->abs_y;
961 }
962
963 static inline int cyapa_sqrt(int delta_x, int delta_y)
964 {
965 int Xk0 = 0;
966 int Xk1;
967 int multi;
968
969 multi = Xk1 = delta_x*delta_x + delta_y*delta_y;
970
971 while (abs(Xk0 - Xk1) > 1) {
972 Xk0 = Xk1;
973 Xk1 = (Xk0 + (multi / Xk0)) / 2;
974 }
975
976 return Xk1;
977 }
978
979 static void cyapa_parse_gen1_data(struct cyapa_i2c *touch,
980 struct cyapa_reg_data_gen1 *reg_data,
981 struct cyapa_report_data *report_data)
982 {
983 int i;
984 int gesture_report_index = 0;
985 int gesture_fingers = 0;
986 int gesture_index = 0;
987
988 /* parse gestures and button data */
989 report_data->button = reg_data->tap_motion & 0x01;
990
991 /* get relative delta X and delta Y. */
992 report_data->rel_deltaX = reg_data->deltax;
993 /* The Y directory of trackpad is the oppsite of Screen. */
994 report_data->rel_deltaY = -reg_data->deltay;
995
996 if (reg_data->tap_motion & 0x02) {
997 report_data->gestures[gesture_report_index++].id
998 = GESTURE_SINGLE_TAP;
999
1000 gesture_fingers = GESTURE_DECODE_FINGERS(GESTURE_SINGLE_TAP);
1001 gesture_index = GESTURE_DECODE_INDEX(GESTURE_SINGLE_TAP);
1002 touch->cur_active_gestures[gesture_fingers]
1003 |= (1UL << gesture_index);
1004 }
1005
1006 if (reg_data->tap_motion & 0x04) {
1007 report_data->gestures[gesture_report_index++].id
1008 = GESTURE_DOUBLE_TAP;
1009
1010 gesture_fingers = GESTURE_DECODE_FINGERS(GESTURE_DOUBLE_TAP);
1011 gesture_index = GESTURE_DECODE_INDEX(GESTURE_DOUBLE_TAP);
1012 touch->cur_active_gestures[gesture_fingers]
1013 |= (1UL << gesture_index);
1014 }
1015
1016 report_data->gestures_count = gesture_report_index;
1017
1018 /* pase fingers touch data */
1019 report_data->touch_fingers
1020 = ((reg_data->touch_fingers > CYAPA_MAX_TOUCHS) ?
1021 (CYAPA_MAX_TOUCHS) : (reg_data->touch_fingers));
1022 report_data->avg_pressure = reg_data->avg_pressure;
1023 report_data->touchs[0].x =
1024 ((reg_data->touch1.rel_xy & 0xF0) << 4)
1025 | reg_data->touch1.rel_x;
1026 report_data->touchs[0].y =
1027 ((reg_data->touch1.rel_xy & 0x0F) << 8)
1028 | reg_data->touch1.rel_y;
1029 report_data->touchs[0].id = 0;
1030
1031 for (i = 0; i < (CYAPA_MAX_TOUCHS-1); i++) {
1032 report_data->touchs[i+1].x =
1033 ((reg_data->touchs[i].rel_xy & 0xF0) << 4)
1034 | reg_data->touchs[i].rel_x;
1035 report_data->touchs[i+1].y =
1036 ((reg_data->touchs[i].rel_xy & 0x0F) << 8)
1037 | reg_data->touchs[i].rel_y;
1038 report_data->touchs[i+1].id = i+1;
1039 }
1040
1041 cyapa_print_report_data(__func__, report_data);
1042 }
1043
1044 static void cyapa_parse_gen2_data(struct cyapa_i2c *touch,
1045 struct cyapa_reg_data_gen2 *reg_data,
1046 struct cyapa_report_data *report_data)
1047 {
1048 int i;
1049 int gesture_fingers = 0;
1050 int gesture_index = 0;
1051
1052 /* bit2-middle button; bit1-right button; bit0-left buttom. */
1053 report_data->button = reg_data->relative_flags & 0x07;
1054
1055 /* get relative delta X and delta Y. */
1056 report_data->rel_deltaX = reg_data->deltax;
1057 /* The Y directory of trackpad is the oppsite of Screen. */
1058 report_data->rel_deltaY = -reg_data->deltay;
1059
1060 /* copy fingers touch data */
1061 report_data->avg_pressure = reg_data->avg_pressure;
1062 report_data->touch_fingers
1063 = ((reg_data->touch_fingers > CYAPA_MAX_TOUCHS) ?
1064 (CYAPA_MAX_TOUCHS) : (reg_data->touch_fingers));
1065 for (i = 0; i < report_data->touch_fingers; i++) {
1066 report_data->touchs[i].x =
1067 ((reg_data->touchs[i].xy & 0xF0) << 4)
1068 | reg_data->touchs[i].x;
1069 report_data->touchs[i].y =
1070 ((reg_data->touchs[i].xy & 0x0F) << 8)
1071 | reg_data->touchs[i].y;
1072 report_data->touchs[i].id = reg_data->touchs[i].id;
1073 }
1074
1075 /* parse gestures */
1076 report_data->gestures_count =
1077 (((reg_data->gesture_count) > CYAPA_ONE_TIME_GESTURES) ?
1078 CYAPA_ONE_TIME_GESTURES : reg_data->gesture_count);
1079 for (i = 0; i < report_data->gestures_count; i++) {
1080 report_data->gestures[i].id = reg_data->gesture[i].id;
1081 report_data->gestures[i].param1 = reg_data->gesture[i].param1;
1082 report_data->gestures[i].param2 = reg_data->gesture[i].param2;
1083
1084 gesture_fingers
1085 = GESTURE_DECODE_FINGERS(report_data->gestures[i].id);
1086 gesture_index
1087 = GESTURE_DECODE_INDEX(report_data->gestures[i].id);
1088 touch->cur_active_gestures[gesture_fingers]
1089 |= (1UL << gesture_index);
1090 }
1091
1092 cyapa_print_report_data(__func__, report_data);
1093 }
1094
1095 void cyapa_set_preferences(struct cyapa_i2c *touch)
1096 {
1097 struct cyapa_preferences *preferences = &touch->preferences;
1098
1099 /* set default setting for hscroll. */
1100 preferences->vscroll.default_threshold = 4;
1101 preferences->vscroll.middle_threshold = 8;
1102 preferences->vscroll.fast_threshold = 16;
1103
1104 /* set default setting for vscroll. */
1105 preferences->hscroll.default_threshold = 4;
1106 preferences->hscroll.middle_threshold = 8;
1107 preferences->hscroll.fast_threshold = 16;
1108
1109 /* set default setting for vscroll. */
1110 preferences->zoom.default_threshold = 8;
1111 preferences->zoom.middle_threshold = 16;
1112 preferences->zoom.fast_threshold = 32;
1113
1114 /* set default setting for platform display aspect ratio adjustment. */
1115 preferences->mouse_ballistic.abs_rise_y = 16;
1116 preferences->mouse_ballistic.abs_run_y = 14;
1117
1118 /* set default setting for ABS FIR filter parameters. */
1119 preferences->mouse_ballistic.fir_abs_enabled = 1;
1120
1121 preferences->mouse_ballistic.fir_abs_depth_slew_count = 5;
1122 preferences->mouse_ballistic.fir_gentle_curve_eccentricity_max = 2;
1123 preferences->mouse_ballistic.fir_moderate_curve_eccentricity_max = 3;
1124
1125 preferences->mouse_ballistic.fir_slow_speed_limit = 4;
1126 preferences->mouse_ballistic.fir_moderate_speed_limit = 7;
1127
1128 preferences->mouse_ballistic.fir_abs_depth_max = 7;
1129 preferences->mouse_ballistic.fir_slow_speed_depth = 7;
1130 preferences->mouse_ballistic.fir_moderate_speed_depth = 7;
1131 preferences->mouse_ballistic.fir_gentle_curve_depth = 5;
1132 preferences->mouse_ballistic.fir_moderate_curve_depth = 6;
1133
1134 /* set default setting for ABS IIR filter parameters. */
1135 preferences->mouse_ballistic.iir_abs_enabled = 1;
1136 preferences->mouse_ballistic.iir_numerator = 1;
1137 preferences->mouse_ballistic.iir_denominator = 2;
1138
1139 /* set default setting for REL speed/acceleration filter parameters. */
1140 preferences->mouse_ballistic.rel_stroke_history_depth = 4;
1141 preferences->mouse_ballistic.rel_medium_speed_threshold = 7;
1142 preferences->mouse_ballistic.rel_fast_speed_threshold = 10;
1143 preferences->mouse_ballistic.rel_flick_speed_threshold = 80;
1144 preferences->mouse_ballistic.rel_motion_numerator = 8;
1145 preferences->mouse_ballistic.rel_medium_speed_numerator = 7;
1146 preferences->mouse_ballistic.rel_motion_denominator = 12;
1147 preferences->mouse_ballistic.rel_acceleration_numerator = 16;
1148 preferences->mouse_ballistic.rel_acceleration_denominator = 100;
1149
1150 /* set default setting for REL IIR filter parameters. */
1151 preferences->mouse_ballistic.rel_iir_acceleration_numerator = 1;
1152 preferences->mouse_ballistic.rel_iir_acceleration_denominator = 8;
1153 preferences->mouse_ballistic.rel_max_acceleration_speed = 900;
1154 }
1155
1156 void cyapa_reset_cursor_filters_data(struct cyapa_i2c *touch)
1157 {
1158 int i;
1159 struct cyapa_cursor_filters *filter = &touch->cursor_filters;
1160
1161 /* reset previous motion data. */
1162 touch->prev_abs_x = -1;
1163 touch->prev_abs_y = -1;
1164 touch->prev_rel_x = 0;
1165 touch->prev_rel_y = 0;
1166
1167 /* reset data used in FIR filter to ABS data. */
1168 filter->fir_curve_type = FIR_CURVE_UNINITIALIZED;
1169 for (i = 0; i < MAX_FIR_DEPTH; i++) {
1170 filter->fir_vectors_x[i] = 0;
1171 filter->fir_vectors_y[i] = 0;
1172 }
1173 filter->fir_x_mod = 0;
1174 filter->fir_y_mod = 0;
1175 filter->fir_abs_depth_x = 0;
1176 filter->fir_abs_depth_y = 0;
1177 filter->fir_abs_prev_depth_x = -1;
1178 filter->fir_abs_prev_depth_y = -1;
1179 filter->fir_abs_depth_slew_counter_x = 1;
1180 filter->fir_abs_depth_slew_counter_y = 1;
1181
1182 /* reset data used in IIR filter to ABS data. */
1183 filter->iir_x = 0xFFFFFFFF;
1184 filter->iir_y = 0xFFFFFFFF;
1185 filter->iir_mod_x = 0;
1186 filter->iir_mod_y = 0;
1187
1188 /* reset data used in compluting relative movement speed category. */
1189 filter->rel_stroke_depth = 0;
1190 filter->rel_stroke_speed = REL_STROKE_SPEED_FAST;
1191
1192 /* reset data used in relative speed/acceleration control. */
1193 filter->rel_residue_x = 0;
1194 filter->rel_residue_y = 0;
1195 filter->rel_prev_residue_accel_x = 0;
1196 filter->rel_prev_residue_accel_y = 0;
1197
1198 /* reset data used in relative IIR filter. */
1199 filter->rel_prev_accel_iir_x = CYAPA_FILTER_EMPTY_DATA;
1200 filter->rel_prev_accel_iir_y = CYAPA_FILTER_EMPTY_DATA;
1201 filter->rel_prev_accel_iir_mod_x = 0;
1202 filter->rel_prev_accel_iir_mod_y = 0;
1203 }
1204
1205 /*Converts modular residues to new scale.
1206 ** This enables residues to persist across interations where various divisors
1207 ** which are used by data filters are modified.
1208 */
1209 inline int cyapa_fir_rescale_modulus(int mod_in, int old_scale, int new_scale)
1210 {
1211 int temp;
1212
1213 if (old_scale <= 1)
1214 return mod_in;
1215
1216 if (new_scale <= old_scale)
1217 return mod_in;
1218
1219 temp = mod_in * new_scale;
1220 temp = temp / old_scale;
1221
1222 return temp;
1223 }
1224
1225 /* Determines the ecentricity, a primitive measure of the degree of curvature,
1226 ** which is used to select FIR characteristics.
1227 */
1228 int cyapa_fir_get_curve_type(struct cyapa_i2c *touch)
1229 {
1230 int i;
1231 int curve_type;
1232 int cur_speed;
1233 int max_speed, min_speed;
1234 int max_speed_x, max_speed_y;
1235 int eccentricity_x, eccentricity_y;
1236 int zero_count_x = 0;
1237 int zero_count_y = 0;
1238 struct cyapa_cursor_filters *filter = &touch->cursor_filters;
1239 struct mouse_ballistic_params *mouse_ballistic
1240 = &touch->preferences.mouse_ballistic;
1241
1242 if (filter->fir_curve_type == FIR_CURVE_UNINITIALIZED) {
1243 if ((filter->fir_abs_depth_x < 2)
1244 || (filter->fir_abs_depth_y < 2)) {
1245 filter->fir_curve_type = FIR_CURVE_MODERATE_SPEED_LINE;
1246 return FIR_CURVE_MODERATE_SPEED_LINE;
1247 }
1248
1249 return filter->fir_curve_type;
1250 }
1251
1252 /* find max speed in X direction. */
1253 max_speed = -100000;
1254 min_speed = 100000;
1255 for (i = 0; i < (filter->fir_abs_depth_x - 1); i++) {
1256 cur_speed = filter->fir_vectors_x[i]
1257 - filter->fir_vectors_x[i+1];
1258
1259 if (cur_speed < min_speed)
1260 min_speed = cur_speed;
1261
1262 if (cur_speed > max_speed)
1263 max_speed = cur_speed;
1264
1265 /* find the count of previous data packages
1266 ** that X direction keeps not moving. */
1267 if ((min_speed == 0) && (max_speed == 0))
1268 zero_count_x = i;
1269 }
1270
1271 if (i > 0)
1272 eccentricity_x = (max_speed - min_speed) / i;
1273 else
1274 eccentricity_x = 0;
1275
1276 max_speed_x = max_speed;
1277
1278 /* find max speed in Y direction. */
1279 max_speed = -100000;
1280 min_speed = 100000;
1281 for (i = 0; i < (filter->fir_abs_depth_y - 1); i++) {
1282 cur_speed = filter->fir_vectors_y[i]
1283 - filter->fir_vectors_y[i+1];
1284
1285 if (cur_speed < min_speed)
1286 min_speed = cur_speed;
1287
1288 if (cur_speed > max_speed)
1289 max_speed = cur_speed;
1290
1291 /* find the count of previous data packages
1292 ** that Y direction keeps not moving. */
1293 if ((min_speed == 0) && (max_speed == 0))
1294 zero_count_y = i;
1295 }
1296
1297 if (i > 0)
1298 eccentricity_y = (max_speed - min_speed) / i;
1299 else
1300 eccentricity_y = 0;
1301
1302 max_speed_y = max_speed;
1303
1304 /* After previous 3 or more data packages reports,
1305 ** finger movement still not detected. */
1306 if ((zero_count_x > 2) && (zero_count_y > 2)) {
1307 filter->fir_curve_type = FIR_CURVE_FULL_STOP;
1308 return FIR_CURVE_FULL_STOP;
1309 }
1310
1311 /* calculate combined speed vectors. */
1312 cur_speed = abs(max_speed_x) + abs(max_speed_y);
1313
1314 /* sort curve line type. */
1315 if (cur_speed < mouse_ballistic->fir_slow_speed_limit)
1316 curve_type = FIR_CURVE_SLOW_SPEED_LINE;
1317 else if (cur_speed < mouse_ballistic->fir_moderate_speed_limit)
1318 curve_type = FIR_CURVE_MODERATE_SPEED_LINE;
1319 else
1320 curve_type = FIR_CURVE_FAST_SPEED_LINE;
1321
1322 /* sort fast speed curve type much more detail
1323 ** based on eccentricity x and y value. */
1324 if (curve_type == FIR_CURVE_FAST_SPEED_LINE) {
1325 if ((eccentricity_x == 1) && (eccentricity_y == 1)) {
1326 curve_type = FIR_CURVE_GENTLE_CURVE;
1327 } else if ((eccentricity_x
1328 == mouse_ballistic->fir_gentle_curve_eccentricity_max)
1329 && (eccentricity_y == 1)) {
1330 curve_type = FIR_CURVE_GENTLE_CURVE;
1331 } else if ((eccentricity_x == 1)
1332 && (eccentricity_y ==
1333 mouse_ballistic->fir_gentle_curve_eccentricity_max)) {
1334 curve_type = FIR_CURVE_GENTLE_CURVE;
1335 } else if ((eccentricity_x
1336 > mouse_ballistic->fir_gentle_curve_eccentricity_max)
1337 && (eccentricity_y
1338 > mouse_ballistic->fir_gentle_curve_eccentricity_max)) {
1339 curve_type = FIR_CURVE_MODERATE_CURVE;
1340 } else if ((eccentricity_x
1341 >= mouse_ballistic->fir_moderate_curve_eccentricity_max)
1342 || (eccentricity_y >=
1343 mouse_ballistic->fir_moderate_curve_eccentricity_max)) {
1344 curve_type = FIR_CURVE_MODERATE_CURVE;
1345 }
1346 }
1347
1348 filter->fir_curve_type = curve_type;
1349
1350 return curve_type;
1351 }
1352
1353 /* Obtain the FIR curve type and obtain the FIR filter depth.
1354 ** Filter depth is a tuning parameter.
1355 */
1356 int cyapa_fir_reset_fifo_depth(struct cyapa_i2c *touch)
1357 {
1358 int curve_type;
1359 int fir_depth;
1360 struct cyapa_cursor_filters *filter = &touch->cursor_filters;
1361 struct mouse_ballistic_params *mouse_ballistic
1362 = &touch->preferences.mouse_ballistic;
1363
1364 curve_type = cyapa_fir_get_curve_type(touch);
1365
1366 switch (curve_type) {
1367 case FIR_CURVE_SLOW_SPEED_LINE:
1368 fir_depth = mouse_ballistic->fir_slow_speed_depth;
1369 break;
1370 case FIR_CURVE_MODERATE_SPEED_LINE:
1371 fir_depth = mouse_ballistic->fir_moderate_speed_depth;
1372 break;
1373 case FIR_CURVE_FAST_SPEED_LINE:
1374 fir_depth = mouse_ballistic->fir_gentle_curve_depth;
1375 break;
1376 case FIR_CURVE_GENTLE_CURVE:
1377 fir_depth = mouse_ballistic->fir_gentle_curve_depth;
1378 break;
1379 case FIR_CURVE_MODERATE_CURVE:
1380 fir_depth = mouse_ballistic->fir_moderate_curve_depth;
1381 break;
1382 case FIR_CURVE_FULL_STOP:
1383 fir_depth = 2;
1384 break;
1385 case FIR_CURVE_CIRCLE:
1386 fir_depth = 0;
1387 break;
1388 default:
1389 fir_depth = mouse_ballistic->fir_slow_speed_depth;
1390 break;
1391 }
1392
1393 /* avoid invalid parameter setting. */
1394 if (fir_depth > mouse_ballistic->fir_abs_depth_max)
1395 fir_depth = mouse_ballistic->fir_abs_depth_max;
1396
1397 filter->fir_effective_max_depth = fir_depth;
1398
1399 return fir_depth;
1400 }
1401
1402 static int cyapa_filter_fir_abs_x(struct cyapa_i2c *touch)
1403 {
1404 int i;
1405 int sum_x, average_x;
1406 int effective_max_depth;
1407 struct cyapa_cursor_filters *filter = &touch->cursor_filters;
1408 struct mouse_ballistic_params *mouse_ballistic
1409 = &touch->preferences.mouse_ballistic;
1410
1411 effective_max_depth = filter->fir_effective_max_depth;
1412
1413 /* set slow speed FIR depth. */
1414 if ((effective_max_depth < filter->fir_abs_depth_x)
1415 && (effective_max_depth < 2)) {
1416 filter->fir_abs_depth_x = effective_max_depth;
1417 filter->fir_abs_depth_slew_counter_x = 0;
1418 }
1419
1420 if (effective_max_depth > filter->fir_abs_depth_x) {
1421 /* count depth change slew value, if less or equal to 0,
1422 ** make depth changed and reset slew value for next time. */
1423 filter->fir_abs_depth_slew_counter_x--;
1424 if (filter->fir_abs_depth_slew_counter_x <= 0) {
1425 filter->fir_abs_depth_slew_counter_x
1426 = mouse_ballistic->fir_abs_depth_slew_count;
1427 filter->fir_abs_depth_x++;
1428 }
1429 }
1430
1431 if (effective_max_depth < filter->fir_abs_depth_x) {
1432 /* count depth change slew value, if less or equal to 0,
1433 ** make depth changed and reset slew value for next time. */
1434 filter->fir_abs_depth_slew_counter_x--;
1435 if (filter->fir_abs_depth_slew_counter_x <= 0) {
1436 filter->fir_abs_depth_slew_counter_x
1437 = mouse_ballistic->fir_abs_depth_slew_count;
1438 filter->fir_abs_depth_x--;
1439 }
1440 }
1441
1442 /* insert new X data. */
1443 for (i = mouse_ballistic->fir_abs_depth_max-1; i > 0; i--)
1444 filter->fir_vectors_x[i] = filter->fir_vectors_x[i-1];
1445 filter->fir_vectors_x[0] = touch->abs_x;
1446
1447 /* calculate and apply ABS FIR filter algorithm to X data. */
1448 for (i = 0; i < filter->fir_abs_depth_x; i++)
1449 sum_x += filter->fir_vectors_x[i];
1450
1451 if (filter->fir_abs_depth_x > 1) {
1452 /* rescale modulus based on ABS FIR depth. */
1453 filter->fir_x_mod = cyapa_fir_rescale_modulus(filter->fir_x_mod,
1454 filter->fir_abs_prev_depth_x, filter->fir_abs_depth_x);
1455 average_x = (sum_x + filter->fir_x_mod)
1456 / filter->fir_abs_depth_x;
1457 filter->fir_x_mod = (sum_x + filter->fir_x_mod)
1458 % filter->fir_abs_depth_x;
1459 } else {
1460 average_x = touch->abs_x;
1461 filter->fir_x_mod = 0;
1462 }
1463
1464 /* store current ABS FIR depth.*/
1465 filter->fir_abs_prev_depth_x = filter->fir_abs_depth_x;
1466
1467 return average_x;
1468 }
1469
1470 static int cyapa_filter_fir_abs_y(struct cyapa_i2c *touch)
1471 {
1472 int i;
1473 int sum_y, average_y;
1474 int effective_max_depth;
1475 struct cyapa_cursor_filters *filter = &touch->cursor_filters;
1476 struct mouse_ballistic_params *mouse_ballistic
1477 = &touch->preferences.mouse_ballistic;
1478
1479 effective_max_depth = filter->fir_effective_max_depth;
1480
1481 /* set slow speed FIR depth. */
1482 if ((effective_max_depth < filter->fir_abs_depth_y)
1483 && (effective_max_depth < 2)) {
1484 filter->fir_abs_depth_y = effective_max_depth;
1485 filter->fir_abs_depth_slew_counter_y = 0;
1486 }
1487
1488 if (effective_max_depth > filter->fir_abs_depth_y) {
1489 /* count depth change slew value, if less or equal to 0,
1490 ** make depth changed and reset slew value for next time. */
1491 filter->fir_abs_depth_slew_counter_y--;
1492 if (filter->fir_abs_depth_slew_counter_y <= 0) {
1493 filter->fir_abs_depth_slew_counter_y
1494 = mouse_ballistic->fir_abs_depth_slew_count;
1495 filter->fir_abs_depth_y++;
1496 }
1497 }
1498
1499 if (effective_max_depth < filter->fir_abs_depth_y) {
1500 /* count depth change slew value, if less or equal to 0,
1501 ** make depth changed and reset slew value for next time. */
1502 filter->fir_abs_depth_slew_counter_y--;
1503 if (filter->fir_abs_depth_slew_counter_y <= 0) {
1504 filter->fir_abs_depth_slew_counter_y
1505 = mouse_ballistic->fir_abs_depth_slew_count;
1506 filter->fir_abs_depth_y--;
1507 }
1508 }
1509
1510 /* insert new Y data. */
1511 for (i = mouse_ballistic->fir_abs_depth_max-1; i > 0; i--)
1512 filter->fir_vectors_y[i] = filter->fir_vectors_y[i-1];
1513 filter->fir_vectors_y[0] = touch->abs_y;
1514
1515 /* calculate and apply ABS FIR filter algorithm to Y data. */
1516 for (i = 0; i < filter->fir_abs_depth_y; i++)
1517 sum_y += filter->fir_vectors_y[i];
1518
1519 if (filter->fir_abs_depth_y > 1) {
1520 /* rescale modulus based on ABS FIR depth. */
1521 filter->fir_y_mod = cyapa_fir_rescale_modulus(filter->fir_y_mod,
1522 filter->fir_abs_prev_depth_y, filter->fir_abs_depth_y);
1523 average_y = (sum_y + filter->fir_y_mod)
1524 / filter->fir_abs_depth_y;
1525 filter->fir_y_mod = (sum_y + filter->fir_y_mod)
1526 % filter->fir_abs_depth_y;
1527 } else {
1528 average_y = touch->abs_y;
1529 filter->fir_y_mod = 0;
1530 }
1531
1532 /* store current ABS FIR depth.*/
1533 filter->fir_abs_prev_depth_y = filter->fir_abs_depth_y;
1534
1535 return average_y;
1536 }
1537
1538 static int cyapa_filter_iir_abs(struct cyapa_i2c *touch,
1539 int *prev_iir,
1540 int *prev_iir_mod,
1541 int pos,
1542 int numerator,
1543 int denominator)
1544 {
1545 int old_iir;
1546 int new_iir;
1547 int iir_mod_prev;
1548 int iir_mod_next;
1549
1550 if (*prev_iir == 0xFFFFFFFF) {
1551 *prev_iir = pos;
1552 *prev_iir_mod = 0;
1553 return pos;
1554 }
1555
1556 if ((numerator == 1) && (denominator == 1)) {
1557 *prev_iir = pos;
1558 *prev_iir_mod = 0;
1559 return pos;
1560 }
1561
1562 if ((numerator > denominator) || (denominator <= 0)) {
1563 *prev_iir = pos;
1564 *prev_iir_mod = 0;
1565 return pos;
1566 }
1567
1568 old_iir = *prev_iir;
1569 iir_mod_prev = *prev_iir_mod;
1570
1571 /* calculate and apply IIR filter to ABS postion value 'pos'. */
1572 new_iir = old_iir * numerator;
1573 pos = pos * (denominator - numerator);
1574 new_iir = new_iir + pos + iir_mod_prev;
1575 iir_mod_next = new_iir % denominator;
1576 new_iir = new_iir / denominator;
1577
1578 /* store current IIR value and IIR mode value
1579 ** for next time calculating.*/
1580 *prev_iir = new_iir;
1581 *prev_iir_mod = iir_mod_next;
1582
1583 return new_iir;
1584 }
1585
1586 inline int cyapa_compute_rel_motion(int abs_pos, int prev_abs_pos)
1587 {
1588 if (prev_abs_pos == -1)
1589 return 0;
1590
1591 return abs_pos - prev_abs_pos;
1592 }
1593
1594 static int cyapa_rel_get_accel_stoke_type(struct cyapa_i2c *touch,
1595 int delta_x,
1596 int delta_y)
1597 {
1598 int i;
1599 int rel_stroke_speed;
1600 int speed_x, speed_y;
1601 int max_speed_x, max_speed_y;
1602 struct cyapa_cursor_filters *filter = &touch->cursor_filters;
1603 struct mouse_ballistic_params *mouse_ballistic
1604 = &touch->preferences.mouse_ballistic;
1605
1606 /* verify mouse ballistic setting for stroke history depth,
1607 ** update it if invliad. */
1608 if (mouse_ballistic->rel_stroke_history_depth
1609 > (REL_STROKE_HISTORY_RECS-1)) {
1610 mouse_ballistic->rel_stroke_history_depth
1611 = REL_STROKE_HISTORY_RECS - 1;
1612 }
1613
1614 for (i = mouse_ballistic->rel_stroke_history_depth-1; i > 0; i--) {
1615 filter->rel_stroke_history[i].x
1616 = filter->rel_stroke_history[i-1].x;
1617 filter->rel_stroke_history[i].y
1618 = filter->rel_stroke_history[i-1].y;
1619 }
1620 filter->rel_stroke_history[0].x = abs(delta_x);
1621 filter->rel_stroke_history[0].y = abs(delta_y);
1622
1623 /* upate storke depth. */
1624 if (filter->rel_stroke_depth
1625 < mouse_ballistic->rel_stroke_history_depth) {
1626 filter->rel_stroke_depth++;
1627 } else {
1628 filter->rel_stroke_depth
1629 = mouse_ballistic->rel_stroke_history_depth;
1630 }
1631
1632 /* find max speed in stroke history. */
1633 max_speed_x = max_speed_y = -100000;
1634 for (i = 0; i < filter->rel_stroke_depth; i++) {
1635 speed_x = filter->rel_stroke_history[i].x;
1636 speed_y = filter->rel_stroke_history[i].y;
1637
1638 if (speed_x > max_speed_x)
1639 max_speed_x = speed_x;
1640
1641 if (speed_y > max_speed_y)
1642 max_speed_y = speed_y;
1643 }
1644
1645 if (max_speed_y > max_speed_x)
1646 max_speed_x = max_speed_y;
1647
1648 /* sort storke speed range based on max stroke history speed. */
1649 if (max_speed_x < mouse_ballistic->rel_medium_speed_threshold) {
1650 rel_stroke_speed = REL_STROKE_SPEED_SLOW;
1651 } else if (max_speed_x > mouse_ballistic->rel_fast_speed_threshold) {
1652 if (max_speed_x < mouse_ballistic->rel_flick_speed_threshold)
1653 rel_stroke_speed = REL_STROKE_SPEED_FAST;
1654 else
1655 rel_stroke_speed = REL_STROKE_SPEED_WARP;
1656 } else {
1657 rel_stroke_speed = REL_STROKE_SPEED_MEDIUM;
1658 }
1659
1660 return rel_stroke_speed;
1661 }
1662
1663 int cyapa_filter_iir_rel(struct cyapa_i2c *touch,
1664 int rel_accel_pos,
1665 int *rel_prev_accel_pos,
1666 int *rel_prev_accel_iir_mod)
1667 {
1668 int old_iir;
1669 int new_iir;
1670 int iir_mod_prev;
1671 int iir_mod_next;
1672 int iir_numerator, iir_denominator;
1673 struct mouse_ballistic_params *mouse_ballistic
1674 = &touch->preferences.mouse_ballistic;
1675
1676 iir_numerator = mouse_ballistic->rel_iir_acceleration_numerator;
1677 iir_denominator = mouse_ballistic->rel_iir_acceleration_denominator;
1678
1679 old_iir = *rel_prev_accel_pos;
1680 iir_mod_prev = *rel_prev_accel_iir_mod;
1681
1682 if ((iir_denominator > 0) && (iir_denominator != iir_numerator)) {
1683 if (old_iir == CYAPA_FILTER_EMPTY_DATA) {
1684 old_iir = rel_accel_pos;
1685 iir_mod_prev = 0;
1686 }
1687
1688 old_iir *= iir_numerator;
1689 new_iir = rel_accel_pos * (iir_denominator - iir_numerator);
1690 new_iir = new_iir + old_iir + iir_mod_prev;
1691 iir_mod_next = new_iir % iir_denominator;
1692 new_iir = new_iir / iir_denominator;
1693
1694 *rel_prev_accel_pos = new_iir;
1695 *rel_prev_accel_iir_mod = iir_mod_next;
1696 } else {
1697 *rel_prev_accel_pos = new_iir = rel_accel_pos;
1698 *rel_prev_accel_iir_mod = 0;
1699 }
1700
1701 return new_iir;
1702 }
1703
1704 /* Adjusts the Y data as reported by the trackpad FW to meet the shape
1705 ** of the user's screen. This is useful to meet some customer test
1706 ** requirements, where a diagonal stroke on the TP is supposed to
1707 ** cause a like-angled diaginal stroke on the PC display device.
1708 */
1709 inline int cyapa_filter_platform_display_aspect_ratio_adjust(
1710 struct cyapa_i2c *touch,
1711 int abs_y)
1712 {
1713 struct mouse_ballistic_params *mouse_ballistic
1714 = &touch->preferences.mouse_ballistic;
1715
1716 abs_y *= mouse_ballistic->abs_rise_y;
1717 if ((mouse_ballistic->abs_run_y > 1)
1718 && (mouse_ballistic->abs_run_y < 10000)) {
1719 abs_y = abs_y / mouse_ballistic->abs_run_y;
1720 }
1721
1722 return abs_y;
1723 }
1724
1725 static void cyapa_filter_cursor_movement(struct cyapa_i2c *touch,
1726 struct cyapa_report_data *report_data)
1727 {
1728 int abs_x, abs_y;
1729 int delta_x, delta_y;
1730 int speed_numerator, speed_denominator;
1731 int acceleration_vector_amplitude = 1;
1732 int acceleration_denominator;
1733 int delta_acceleration_x = 0;
1734 int delta_acceleration_y = 0;
1735 struct cyapa_cursor_filters *filter = &touch->cursor_filters;
1736 struct mouse_ballistic_params *mouse_ballistic
1737 = &touch->preferences.mouse_ballistic;
1738
1739 /*
1740 ** 1. Input ABS raw data.
1741 */
1742 touch->abs_x = abs_x = report_data->touchs[0].x;
1743 touch->abs_y = abs_y = report_data->touchs[0].y;
1744
1745 /* adjust Y data as reported by firware to meet the
1746 ** shape of the usre's screen firstly. */
1747 touch->abs_y = cyapa_filter_platform_display_aspect_ratio_adjust(touch,
1748 touch->abs_y);
1749
1750 /*
1751 ** 2. Apply FIR filter to ABS raw data.
1752 */
1753 if (mouse_ballistic->fir_abs_enabled) {
1754 cyapa_fir_reset_fifo_depth(touch);
1755 abs_x = cyapa_filter_fir_abs_x(touch);
1756 abs_y = cyapa_filter_fir_abs_y(touch);
1757 }
1758
1759 /*
1760 ** 3. Apply IIR filter to FIR filtered ABS data.
1761 */
1762 if (mouse_ballistic->iir_abs_enabled) {
1763 abs_x = cyapa_filter_iir_abs(touch,
1764 &filter->iir_x,
1765 &filter->iir_mod_x,
1766 abs_x,
1767 mouse_ballistic->iir_numerator,
1768 mouse_ballistic->iir_denominator);
1769 abs_y = cyapa_filter_iir_abs(touch,
1770 &filter->iir_y,
1771 &filter->iir_mod_y,
1772 abs_y,
1773 mouse_ballistic->iir_numerator,
1774 mouse_ballistic->iir_denominator);
1775 touch->abs_x = abs_x;
1776 touch->abs_y = abs_y;
1777 }
1778
1779 /*
1780 ** 4. Calculate delta movement value.
1781 */
1782 delta_x = cyapa_compute_rel_motion(touch->abs_x, touch->prev_abs_x);
1783 delta_y = cyapa_compute_rel_motion(touch->abs_y, touch->prev_abs_y);
1784 touch->prev_abs_x = touch->abs_x;
1785 touch->prev_abs_y = touch->abs_y;
1786
1787 /*
1788 ** 5. Apply speed/acceleration control.
1789 */
1790 /* Obtain relative movement speed category
1791 ** for use in computing speed coefficients. */
1792 filter->rel_stroke_speed
1793 = cyapa_rel_get_accel_stoke_type(touch, delta_x, delta_y);
1794
1795 /* Compute Acceleration Component. */
1796 if ((touch->prev_rel_x == CYAPA_FILTER_EMPTY_DATA)
1797 || (touch->prev_rel_y == CYAPA_FILTER_EMPTY_DATA)) {
1798 /* debounce before start filter.*/
1799 touch->prev_rel_x = delta_x;
1800 touch->prev_rel_y = delta_y;
1801 filter->rel_residue_x = 0;
1802 filter->rel_residue_y = 0;
1803 filter->rel_prev_accel_iir_x = CYAPA_FILTER_EMPTY_DATA;
1804 filter->rel_prev_accel_iir_y = CYAPA_FILTER_EMPTY_DATA;
1805 filter->rel_prev_accel_iir_mod_x = 0;
1806 filter->rel_prev_accel_iir_mod_y = 0;
1807 filter->rel_prev_residue_accel_x = 0;
1808 filter->rel_prev_residue_accel_y = 0;
1809
1810 touch->rel_x = delta_x;
1811 touch->rel_y = delta_y;
1812 report_data->rel_deltaX = delta_x;
1813 report_data->rel_deltaY = delta_y;
1814
1815 return;
1816 }
1817
1818 /* sort speed numerator and denominator. */
1819 if (filter->rel_stroke_speed == REL_STROKE_SPEED_SLOW) {
1820 speed_numerator = mouse_ballistic->rel_motion_numerator;
1821 speed_denominator = mouse_ballistic->rel_motion_denominator;
1822 } else {
1823 speed_numerator = mouse_ballistic->rel_medium_speed_numerator;
1824 speed_denominator = mouse_ballistic->rel_motion_denominator;
1825 }
1826
1827 /* apply speed/acceleration control. */
1828 delta_x *= speed_numerator;
1829 delta_y *= speed_numerator;
1830
1831 if (speed_denominator > 1) {
1832 delta_x += filter->rel_residue_x;
1833 filter->rel_residue_x = delta_x % speed_denominator;
1834 delta_x /= speed_denominator;
1835
1836 delta_y += filter->rel_residue_y;
1837 filter->rel_residue_y = delta_y % speed_denominator;
1838 delta_y /= speed_denominator;
1839 }
1840
1841 if (filter->rel_stroke_speed >= REL_STROKE_SPEED_FAST) {
1842 acceleration_vector_amplitude = 10;
1843 acceleration_vector_amplitude
1844 *= mouse_ballistic->rel_acceleration_numerator;
1845 acceleration_denominator
1846 = mouse_ballistic->rel_acceleration_denominator;
1847
1848 touch->prev_rel_x = delta_x;
1849 touch->prev_rel_y = delta_y;
1850
1851 delta_acceleration_x = delta_x * acceleration_vector_amplitude;
1852 delta_acceleration_y = delta_y * acceleration_vector_amplitude;
1853
1854 if (acceleration_denominator > 1) {
1855 delta_acceleration_x
1856 += filter->rel_prev_residue_accel_x;
1857 filter->rel_prev_residue_accel_x = delta_acceleration_x
1858 % acceleration_denominator;
1859 delta_acceleration_x /= acceleration_denominator;
1860
1861 delta_acceleration_y
1862 += filter->rel_prev_residue_accel_y;
1863 filter->rel_prev_residue_accel_y = delta_acceleration_y
1864 % acceleration_denominator;
1865 delta_acceleration_y /= acceleration_denominator;
1866 }
1867
1868 delta_x = delta_acceleration_x;
1869 delta_y = delta_acceleration_y;
1870 }
1871
1872 /*
1873 ** 6. Apply IIR filter to relative data.
1874 */
1875 delta_x = cyapa_filter_iir_rel(touch, delta_x,
1876 &filter->rel_prev_accel_iir_x,
1877 &filter->rel_prev_accel_iir_mod_x);
1878 delta_y = cyapa_filter_iir_rel(touch, delta_y,
1879 &filter->rel_prev_accel_iir_y,
1880 &filter->rel_prev_accel_iir_mod_y);
1881
1882 if (delta_x > mouse_ballistic->rel_max_acceleration_speed)
1883 delta_x = mouse_ballistic->rel_max_acceleration_speed;
1884 else if (delta_x < -mouse_ballistic->rel_max_acceleration_speed)
1885 delta_x = -mouse_ballistic->rel_max_acceleration_speed;
1886
1887 if (delta_y > mouse_ballistic->rel_max_acceleration_speed)
1888 delta_y = mouse_ballistic->rel_max_acceleration_speed;
1889 else if (delta_y < -mouse_ballistic->rel_max_acceleration_speed)
1890 delta_y = -mouse_ballistic->rel_max_acceleration_speed;
1891
1892 touch->rel_x = delta_x;
1893 touch->rel_y = delta_y;
1894 report_data->rel_deltaX = delta_x;
1895 report_data->rel_deltaY = delta_y;
1896
1897 return;
1898 }
1899
1900 static inline void cyapa_report_fingers(struct input_dev *input, int fingers)
1901 {
1902 if (fingers) {
1903 input_report_key(input, BTN_TOOL_FINGER, (fingers == 1));
1904 input_report_key(input, BTN_TOOL_DOUBLETAP, (fingers == 2));
1905 input_report_key(input, BTN_TOOL_TRIPLETAP, (fingers == 3));
1906 input_report_key(input, BTN_TOOL_QUADTAP, (fingers > 3));
1907 } else {
1908 input_report_key(input, BTN_TOOL_FINGER, 0);
1909 input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
1910 input_report_key(input, BTN_TOOL_TRIPLETAP, 0);
1911 input_report_key(input, BTN_TOOL_QUADTAP, 0);
1912 }
1913 }
1914
1915 static void cyapa_process_prev_gesture_report(struct cyapa_i2c *touch,
1916 struct cyapa_report_data *report_data)
1917 {
1918 int i, j;
1919 unsigned long gesture_diff;
1920 struct input_dev *input = touch->input;
1921 struct input_dev *input_kbd = touch->input_kbd;
1922
1923 for (i = 0; i < MAX_FINGERS; i++) {
1924 /* get all diffenent gestures in prev and cur. */
1925 gesture_diff
1926 = touch->prev_active_gestures[i]
1927 ^ touch->cur_active_gestures[i];
1928 /* get all prev gestures that has been canceled in cur. */
1929 gesture_diff = gesture_diff & touch->prev_active_gestures[i];
1930 if (gesture_diff) {
1931 for (j = 0; j < (sizeof(unsigned long)*8); j++) {
1932 /* cancel previous exists gesture. */
1933 if ((gesture_diff >> j) & 1UL) {
1934 switch (GESTURE_ID_CODE(i, j)) {
1935 case GESTURE_PALM_REJECTIOIN:
1936 break;
1937 case GESTURE_SINGLE_TAP:
1938 break;
1939 case GESTURE_DOUBLE_TAP:
1940 break;
1941 case GESTURE_TAP_AND_HOLD:
1942 break;
1943 case GESTURE_EDGE_MOTION:
1944 break;
1945 case GESTURE_DRAG:
1946 touch->prev_abs_x = -1;
1947 touch->prev_abs_y = -1;
1948
1949 if (touch->platform_data
1950 ->use_absolute_mode) {
1951 input_report_key(input,
1952 BTN_TOUCH, 0);
1953 input_report_abs(input,
1954 ABS_PRESSURE,
1955 0);
1956 cyapa_report_fingers(
1957 input, 0);
1958 input_report_key(input,
1959 BTN_LEFT, 0);
1960 input_sync(input);
1961 }
1962
1963 cyapa_reset_cursor_filters_data(
1964 touch);
1965
1966 break;
1967 case GESTURE_2F_ZOOM_IN:
1968 touch->zoomin_delta = 0;
1969 touch->zoom_trigged = 0;
1970 input_report_key(input_kbd,
1971 KEY_LEFTCTRL, 1);
1972 input_sync(input_kbd);
1973 input_report_key(input_kbd,
1974 KEY_LEFTCTRL, 0);
1975 input_sync(input_kbd);
1976 break;
1977 case GESTURE_2F_ZOOM_OUT:
1978 touch->zoomout_delta = 0;
1979 touch->zoom_trigged = 0;
1980 input_report_key(input_kbd,
1981 KEY_LEFTCTRL, 1);
1982 input_sync(input_kbd);
1983 input_report_key(input_kbd,
1984 KEY_LEFTCTRL, 0);
1985 input_sync(input_kbd);
1986 break;
1987 case GESTURE_SCROLL_UP:
1988 case GESTURE_2F_SCROLL_UP:
1989 touch->delta_scroll_up = 0;
1990 break;
1991 case GESTURE_SCROLL_DOWN:
1992 case GESTURE_2F_SCROLL_DOWN:
1993 touch->delta_scroll_down = 0;
1994 break;
1995 case GESTURE_SCROLL_LEFT:
1996 case GESTURE_2F_SCROLL_LEFT:
1997 input_report_key(input_kbd,
1998 KEY_LEFTSHIFT, 1);
1999 input_sync(input_kbd);
2000 input_report_key(input_kbd,
2001 KEY_LEFTSHIFT, 0);
2002 input_sync(input_kbd);
2003 touch->hscroll_canceled = 1;
2004 touch->hscroll_left = 0;
2005 touch->delta_scroll_left = 0;
2006 break;
2007 case GESTURE_SCROLL_RIGHT:
2008 case GESTURE_2F_SCROLL_RIGHT:
2009 input_report_key(input_kbd,
2010 KEY_LEFTSHIFT, 1);
2011 input_sync(input_kbd);
2012 input_report_key(input_kbd,
2013 KEY_LEFTSHIFT, 0);
2014 input_sync(input_kbd);
2015 touch->hscroll_canceled = 1;
2016 touch->hscroll_right = 0;
2017 touch->delta_scroll_right = 0;
2018 break;
2019 case GESTURE_2F_ROTATE:
2020 break;
2021 case GESTURE_2F_PINCH:
2022 break;
2023 case GESTURE_2F_TAP:
2024 break;
2025 case GESTURE_2F_DRAG:
2026 if (touch->platform_data
2027 ->use_absolute_mode) {
2028 input_report_key(input,
2029 BTN_TOUCH, 0);
2030 input_report_abs(input,
2031 ABS_PRESSURE,
2032 0);
2033 input_report_key(input,
2034 BTN_LEFT, 0);
2035 cyapa_report_fingers(
2036 input, 0);
2037 input_sync(input);
2038 }
2039
2040 touch->gesture_2F_drag_started
2041 = 0;
2042 touch->prev_abs_x = -1;
2043 touch->prev_abs_y = -1;
2044 break;
2045 case GESTURE_FLICK:
2046 case GESTURE_2F_FLICK:
2047 case GESTURE_3F_FLICK:
2048 case GESTURE_4F_FLICK:
2049 case GESTURE_5F_FLICK:
2050 break;
2051 default:
2052 break;
2053 }
2054 }
2055 }
2056 }
2057 }
2058 }
2059
2060 static void cyapa_gesture_report(struct cyapa_i2c *touch,
2061 struct cyapa_report_data *report_data,
2062 struct cyapa_gesture *gesture)
2063 {
2064 struct input_dev *input = touch->input;
2065 struct input_dev *input_wheel = touch->input_wheel;
2066 struct input_dev *input_kbd = touch->input_kbd;
2067 int delta = 0;
2068 struct cyapa_preferences *preferences = &touch->preferences;
2069 int threshold = 0;
2070 int value = 0;
2071
2072 switch (gesture->id) {
2073 case GESTURE_PALM_REJECTIOIN:
2074 /* when palm rejection gesture is trigged, do not move cursor
2075 ** any more, just operation as no finger touched on trackpad.
2076 */
2077 if (touch->platform_data->use_absolute_mode) {
2078 input_report_key(input, BTN_TOUCH, 0);
2079 input_report_abs(input, ABS_PRESSURE, 0);
2080 input_report_abs(input, ABS_TOOL_WIDTH, 0);
2081 cyapa_report_fingers(input, 0);
2082 }
2083
2084 touch->prev_abs_x = -1;
2085 touch->prev_abs_y = -1;
2086
2087 input_report_key(input, BTN_LEFT, report_data->button & 0x01);
2088 input_report_key(input, BTN_RIGHT, report_data->button & 0x02);
2089 input_report_key(input, BTN_MIDDLE, report_data->button & 0x04);
2090
2091 input_sync(input);
2092
2093 DBGPRINTK(("%s: report palm rejection\n", __func__));
2094 break;
2095 case GESTURE_SINGLE_TAP:
2096 if (touch->platform_data->use_absolute_mode) {
2097 input_report_key(input, BTN_TOUCH, 0);
2098 input_report_abs(input, ABS_PRESSURE, 0);
2099 input_report_key(input, BTN_LEFT, 0);
2100 input_sync(input);
2101
2102 /* in absolute mode use cyapa_report_fingers(input, N)
2103 ** to trigger click.
2104 ** when N change from small to large,
2105 ** clieck with be trigged.*/
2106 break;
2107 }
2108
2109 input_report_key(input, BTN_LEFT, 1);
2110 input_sync(input);
2111
2112 input_report_key(input, BTN_LEFT, 0);
2113 input_sync(input);
2114
2115 DBGPRINTK(("%s: report single tap\n", __func__));
2116 break;
2117 case GESTURE_DOUBLE_TAP:
2118 if (touch->platform_data->use_absolute_mode) {
2119 input_report_key(input, BTN_TOUCH, 0);
2120 input_report_abs(input, ABS_PRESSURE, 0);
2121 input_report_key(input, BTN_LEFT, 0);
2122 input_report_key(input, BTN_RIGHT, 0);
2123 input_sync(input);
2124 }
2125
2126 input_report_key(input, BTN_LEFT, 1);
2127 input_sync(input);
2128
2129 input_report_key(input, BTN_LEFT, 0);
2130 input_sync(input);
2131
2132 input_report_key(input, BTN_LEFT, 1);
2133 input_sync(input);
2134
2135 input_report_key(input, BTN_LEFT, 0);
2136 input_sync(input);
2137
2138 DBGPRINTK(("%s: report double tap\n", __func__));
2139 break;
2140 case GESTURE_TAP_AND_HOLD:
2141 /* one finger click and hold for more than definitioin time,
2142 ** then to do something. */
2143 DBGPRINTK(("%s: no gesture for Tap and hold yet.\n", __func__));
2144 break;
2145 case GESTURE_EDGE_MOTION:
2146 DBGPRINTK(("%s: no gesture for edge motion yet.\n", __func__));
2147 break;
2148 case GESTURE_DRAG:
2149 /* 1-finger drag. 1-finger double click and hold,
2150 ** then move the finger. */
2151 if (touch->platform_data->use_absolute_mode) {
2152 touch->xy_touchs_included_bits = 0x01;
2153 cyapa_calculate_abs_xy(touch, report_data);
2154
2155 input_report_key(input, BTN_TOUCH, 1);
2156 input_report_abs(input, ABS_X, touch->abs_x);
2157 input_report_abs(input, ABS_Y, touch->abs_y);
2158 input_report_abs(input, ABS_PRESSURE,
2159 report_data->avg_pressure);
2160 cyapa_report_fingers(input, 1);
2161 input_report_key(input, BTN_LEFT, 1);
2162 input_sync(input);
2163 } else {
2164 cyapa_filter_cursor_movement(touch, report_data);
2165
2166 input_report_rel(input, REL_X, report_data->rel_deltaX);
2167 input_report_rel(input, REL_Y, report_data->rel_deltaY);
2168 input_report_key(input, BTN_LEFT, 1);
2169 input_sync(input);
2170 }
2171
2172 DBGPRINTK(("%s: 1 finger drag.\n", __func__));
2173 break;
2174 case GESTURE_2F_ZOOM_IN:
2175 delta = gesture->param2;
2176 /* no zoom delta. */
2177 if (delta <= 0)
2178 break;
2179 touch->zoomin_delta += delta;
2180
2181 if (touch->zoom_trigged == 0) {
2182 input_report_key(input_kbd, KEY_LEFTCTRL, 0);
2183 input_sync(input_kbd);
2184 input_report_key(input_kbd, KEY_LEFTCTRL, 1);
2185 input_sync(input_kbd);
2186 touch->zoom_trigged = 1;
2187 } else {
2188 if (touch->zoomin_delta
2189 <= preferences->zoom.default_threshold) {
2190 threshold = 0;
2191 value = 1;
2192 } else if (touch->zoomin_delta
2193 > preferences->zoom.fast_threshold) {
2194 threshold = 2;
2195 value = touch->zoomin_delta
2196 / preferences->zoom.fast_threshold;
2197 touch->zoomin_delta
2198 %= preferences->zoom.fast_threshold;
2199 } else {
2200 threshold = 1;
2201 value = 1;
2202 touch->zoomin_delta = 0;
2203 }
2204
2205 while (threshold > 0) {
2206 input_report_rel(input_wheel, REL_WHEEL, value);
2207 input_sync(input_wheel);
2208 threshold--;
2209 }
2210 }
2211
2212 DBGPRINTK(("%s: 2F zoom in.\n", __func__));
2213 break;
2214 case GESTURE_2F_ZOOM_OUT:
2215 delta = gesture->param2;
2216 /* no zoom delta. */
2217 if (delta <= 0)
2218 break;
2219 touch->zoomout_delta += delta;
2220
2221 if (touch->zoom_trigged == 0) {
2222 input_report_key(input_kbd, KEY_LEFTCTRL, 0);
2223 input_sync(input_kbd);
2224 input_report_key(input_kbd, KEY_LEFTCTRL, 1);
2225 input_sync(input_kbd);
2226 touch->zoom_trigged = 1;
2227 } else {
2228 value = 1;
2229 if (touch->zoomout_delta
2230 <= preferences->zoom.default_threshold) {
2231 threshold = 0;
2232 value = 1;
2233 } else if (touch->zoomout_delta
2234 > preferences->zoom.fast_threshold) {
2235 threshold = 2;
2236 value = touch->zoomout_delta
2237 / preferences->zoom.fast_threshold;
2238 touch->zoomout_delta
2239 %= preferences->zoom.fast_threshold;
2240 } else {
2241 threshold = 1;
2242 value = 1;
2243 touch->zoomout_delta = 0;
2244 }
2245
2246 while (threshold > 0) {
2247 input_report_rel(input_wheel,
2248 REL_WHEEL,
2249 -value);
2250 input_sync(input_wheel);
2251 threshold--;
2252 }
2253 }
2254
2255 DBGPRINTK(("%s: 2F zoom out.\n", __func__));
2256 break;
2257 case GESTURE_SCROLL_UP:
2258 case GESTURE_2F_SCROLL_UP:
2259 if (touch->hscroll_canceled) {
2260 /* avoid VScroll miss trigged as HScroll. */
2261 touch->hscroll_canceled = 0;
2262 input_report_key(input_kbd, KEY_LEFTSHIFT, 0);
2263 input_sync(input_kbd);
2264
2265 break;
2266 }
2267
2268 delta = gesture->param2;
2269 threshold = preferences->vscroll.default_threshold;
2270 value = 1;
2271 touch->delta_scroll_up += delta;
2272
2273 if (touch->delta_scroll_up <= 0) {
2274 /* no scroll move, it's not need to report. */
2275 touch->delta_scroll_up = 0;
2276 break;
2277 }
2278
2279 if (touch->delta_scroll_up < threshold) {
2280 /* keep small movement also can work. */
2281 input_report_rel(input_wheel, REL_WHEEL, value);
2282 input_sync(input_wheel);
2283
2284 touch->delta_scroll_up = 0;
2285 break;
2286 }
2287
2288 if (touch->delta_scroll_up
2289 > preferences->vscroll.fast_threshold) {
2290 /* fast scroll, reset threshold value. */
2291 threshold = 1;
2292 value = 16;
2293 } else {
2294 /* middle scroll speed. */
2295 threshold = 2;
2296 value = 2;
2297 }
2298
2299 while (touch->delta_scroll_up >= threshold) {
2300 input_report_rel(input_wheel,
2301 REL_WHEEL,
2302 value*2/threshold);
2303 input_sync(input_wheel);
2304
2305 touch->delta_scroll_up -= threshold*value;
2306 }
2307
2308 DBGPRINTK(("%s: scroll up, fingers=%d\n",
2309 __func__, report_data->touch_fingers));
2310 break;
2311 case GESTURE_SCROLL_DOWN:
2312 case GESTURE_2F_SCROLL_DOWN:
2313 if (touch->hscroll_canceled) {
2314 /* avoid VScroll miss trigged as HScroll. */
2315 touch->hscroll_canceled = 0;
2316 input_report_key(input_kbd, KEY_LEFTSHIFT, 0);
2317 input_sync(input_kbd);
2318
2319 break;
2320 }
2321
2322 delta = gesture->param2;
2323 threshold = preferences->vscroll.default_threshold;
2324 value = 1;
2325 touch->delta_scroll_down += delta;
2326
2327 if (touch->delta_scroll_down <= 0) {
2328 /* no scroll move, it's not need to report. */
2329 touch->delta_scroll_down = 0;
2330 break;
2331 }
2332
2333 if (touch->delta_scroll_down < threshold) {
2334 /* keep small movement also can work. */
2335 input_report_rel(input_wheel, REL_WHEEL, -value);
2336 input_sync(input_wheel);
2337
2338 touch->delta_scroll_down = 0;
2339 break;
2340 }
2341
2342 if (touch->delta_scroll_down
2343 > preferences->vscroll.fast_threshold) {
2344 /* fast scroll, reset threshold value. */
2345 threshold = 1;
2346 value = 16;
2347 } else {
2348 /* middle scroll speed. */
2349 threshold = 2;
2350 value = 2;
2351 }
2352
2353 while (touch->delta_scroll_down >= threshold) {
2354 input_report_rel(input_wheel,
2355 REL_WHEEL,
2356 -value*2/threshold);
2357 input_sync(input_wheel);
2358
2359 touch->delta_scroll_down -= threshold*value;
2360 }
2361
2362 DBGPRINTK(("%s: scroll down, finger=%d\n",
2363 __func__, report_data->touch_fingers));
2364 break;
2365 case GESTURE_SCROLL_LEFT:
2366 case GESTURE_2F_SCROLL_LEFT:
2367 delta = gesture->param2;
2368 if (0 == touch->hscroll_left) {
2369 /* to report left shift firstly inorder to avoid miss
2370 ** trig vscroll. because, for 0.9.101 chromium os,
2371 ** it seems that when left shift is pressed,
2372 ** then scroll soon, the combined gesture won't
2373 ** take effect soon, it will have some delay.
2374 ** So add a debounce to avoid this issue.
2375 */
2376 input_report_key(input_kbd, KEY_LEFTSHIFT, 0);
2377 input_sync(input_kbd);
2378 input_report_key(input_kbd, KEY_LEFTSHIFT, 1);
2379 input_sync(input_kbd);
2380 touch->hscroll_left = delta;
2381 } else {
2382 threshold = preferences->hscroll.default_threshold;
2383 value = 1;
2384 touch->delta_scroll_left += delta;
2385
2386 if (touch->delta_scroll_left <= 0) {
2387 /* no scroll move, it's not need to report. */
2388 touch->delta_scroll_left = 0;
2389 break;
2390 }
2391
2392 if (touch->delta_scroll_left < threshold) {
2393 /* keep small movement also can work. */
2394 input_report_rel(input_wheel, REL_WHEEL, value);
2395 input_sync(input_wheel);
2396
2397 touch->delta_scroll_left = 0;
2398 break;
2399 }
2400
2401 if (touch->delta_scroll_left
2402 > preferences->hscroll.fast_threshold) {
2403 /* fast scroll, reset threshold value. */
2404 threshold = 1;
2405 value = 16;
2406 } else {
2407 /* middle scroll speed. */
2408 threshold = 2;
2409 value = 2;
2410 }
2411
2412 while (touch->delta_scroll_left >= threshold) {
2413 input_report_rel(input_wheel,
2414 REL_WHEEL,
2415 value*2/threshold);
2416 input_sync(input_wheel);
2417
2418 touch->delta_scroll_left -= threshold*value;
2419 }
2420 }
2421
2422 DBGPRINTK(("%s: scroll left, finger=%d\n",
2423 __func__, report_data->touch_fingers));
2424 break;
2425 case GESTURE_SCROLL_RIGHT:
2426 case GESTURE_2F_SCROLL_RIGHT:
2427 delta = gesture->param2;
2428 if (0 == touch->hscroll_right) {
2429 input_report_key(input_kbd, KEY_LEFTSHIFT, 0);
2430 input_sync(input_kbd);
2431 input_report_key(input_kbd, KEY_LEFTSHIFT, 1);
2432 input_sync(input_kbd);
2433 touch->hscroll_right = delta;
2434 } else {
2435 threshold = preferences->hscroll.default_threshold;
2436 value = 1;
2437 touch->delta_scroll_right += delta;
2438
2439 if (touch->delta_scroll_right <= 0) {
2440 /* no scroll move, it's not need to report. */
2441 touch->delta_scroll_right = 0;
2442 break;
2443 }
2444
2445 if (touch->delta_scroll_right < threshold) {
2446 /* keep small movement also can work. */
2447 input_report_rel(input_wheel,
2448 REL_WHEEL,
2449 -value);
2450 input_sync(input_wheel);
2451
2452 touch->delta_scroll_right = 0;
2453 break;
2454 }
2455
2456 if (touch->delta_scroll_right
2457 > preferences->hscroll.fast_threshold) {
2458 /* fast scroll, reset threshold value. */
2459 threshold = 1;
2460 value = 16;
2461 } else {
2462 /* middle scroll speed. */
2463 threshold = 2;
2464 value = 2;
2465 }
2466
2467 while (touch->delta_scroll_right >= threshold) {
2468 input_report_rel(input_wheel,
2469 REL_WHEEL,
2470 -value*2/threshold);
2471 input_sync(input_wheel);
2472
2473 touch->delta_scroll_right -= threshold*value;
2474 }
2475 }
2476
2477 DBGPRINTK(("%s: scroll right, finger=%d\n",
2478 __func__, report_data->touch_fingers));
2479 break;
2480 case GESTURE_2F_ROTATE:
2481 DBGPRINTK(("%s: 2 finger rotate.\n", __func__));
2482 break;
2483 case GESTURE_2F_PINCH:
2484 DBGPRINTK(("%s: 2 finger pinch.\n", __func__));
2485 break;
2486 case GESTURE_2F_TAP:
2487 /* 2-finger tap, active like right button press and relase. */
2488 if (touch->platform_data->use_absolute_mode) {
2489 input_report_key(input, BTN_TOUCH, 0);
2490 input_report_abs(input, ABS_PRESSURE, 0);
2491 input_report_key(input, BTN_LEFT, 0);
2492 input_report_key(input, BTN_RIGHT, 0);
2493 input_sync(input);
2494 }
2495
2496 input_report_key(input, BTN_RIGHT, 1);
2497 input_sync(input);
2498
2499 input_report_key(input, BTN_RIGHT, 0);
2500 input_sync(input);
2501
2502 DBGPRINTK(("%s: report 2 fingers tap, \
2503 active like right button.\n", __func__));
2504 break;
2505 case GESTURE_2F_DRAG:
2506 /* first finger click and hold,
2507 ** and second finger moving for dragging. */
2508 if (touch->gesture_2F_drag_started == 0) {
2509 touch->xy_touchs_included_bits = 0x01;
2510 touch->prev_abs_x = -1;
2511 touch->prev_abs_y = -1;
2512 cyapa_calculate_abs_xy(touch, report_data);
2513
2514 /* firstly, move move cursor to the target for drag. */
2515 input_report_key(input, BTN_TOUCH, 1);
2516 if (touch->platform_data->use_absolute_mode) {
2517 input_report_abs(input, ABS_X, touch->abs_x);
2518 input_report_abs(input, ABS_Y, touch->abs_y);
2519 input_report_abs(input,
2520 ABS_PRESSURE,
2521 report_data->avg_pressure);
2522 cyapa_report_fingers(input, 1);
2523 }
2524 input_report_key(input, BTN_LEFT, 0);
2525 input_report_key(input, BTN_RIGHT, 0);
2526 input_sync(input);
2527
2528 /* second, stop cursor on the target for drag. */
2529 touch->prev_abs_x = -1;
2530 touch->prev_abs_y = -1;
2531 if (touch->platform_data->use_absolute_mode) {
2532 input_report_key(input, BTN_TOUCH, 0);
2533 input_report_abs(input, ABS_PRESSURE, 0);
2534 input_sync(input);
2535 }
2536
2537 /* third, select the target for drag. */
2538 input_report_key(input, BTN_LEFT, 1);
2539 input_sync(input);
2540
2541 /* go to step four. */
2542 touch->gesture_2F_drag_started = 1;
2543 }
2544
2545 /* fourth, move cursor for dragging. */
2546 touch->xy_touchs_included_bits = 0x02;
2547 cyapa_calculate_abs_xy(touch, report_data);
2548
2549 if (touch->platform_data->use_absolute_mode) {
2550 input_report_key(input, BTN_TOUCH, 1);
2551 input_report_abs(input, ABS_X, touch->abs_x);
2552 input_report_abs(input, ABS_Y, touch->abs_y);
2553 input_report_abs(input,
2554 ABS_PRESSURE,
2555 report_data->avg_pressure);
2556 cyapa_report_fingers(input, 1);
2557 } else {
2558 input_report_rel(input, REL_X, report_data->rel_deltaX);
2559 input_report_rel(input, REL_Y, report_data->rel_deltaY);
2560 input_sync(input);
2561 }
2562 input_report_key(input, BTN_LEFT, 1);
2563 input_sync(input);
2564
2565 DBGPRINTK(("%s: report 2 fingers drag\n", __func__));
2566 break;
2567 case GESTURE_FLICK:
2568 case GESTURE_2F_FLICK:
2569 case GESTURE_3F_FLICK:
2570 case GESTURE_4F_FLICK:
2571 case GESTURE_5F_FLICK:
2572 touch->xy_touchs_included_bits = report_data->touch_fingers;
2573 DBGPRINTK(("%s: no flick gesture supported yet, , finger=%d\n",
2574 __func__, report_data->touch_fingers));
2575 break;
2576 default:
2577 DBGPRINTK(("%s: default, unknown gesture for reporting.\n",
2578 __func__));
2579 break;
2580 }
2581 }
2582
2583 static int cyapa_rel_input_report_data(struct cyapa_i2c *touch,
2584 struct cyapa_report_data *report_data)
2585 {
2586 int i;
2587 struct input_dev *input = touch->input;
2588
2589 /* step 1: process gestures firstly if trigged. */
2590 cyapa_process_prev_gesture_report(touch, report_data);
2591 if (report_data->gestures_count > 0) {
2592 DBGPRINTK(("%s: do gesture report, gestures_count = %d\n",
2593 __func__, report_data->gestures_count));
2594 /* gesture trigged */
2595 for (i = 0; i < report_data->gestures_count; i++) {
2596 cyapa_gesture_report(touch,
2597 report_data,
2598 &report_data->gestures[i]);
2599 }
2600
2601 /* when gestures are trigged, cursor should not move. */
2602 } else {
2603 /* when multi-fingers touched, cursour should also not move. */
2604 if (report_data->touch_fingers == 1) {
2605 /* apply cursor movement filters to
2606 ** improve cursor performance. */
2607 cyapa_filter_cursor_movement(touch, report_data);
2608
2609 /* Report the deltas */
2610 input_report_rel(input, REL_X, report_data->rel_deltaX);
2611 input_report_rel(input, REL_Y, report_data->rel_deltaY);
2612 } else {
2613 cyapa_reset_cursor_filters_data(touch);
2614 }
2615
2616 /* Report the button event */
2617 input_report_key(input, BTN_LEFT,
2618 (report_data->button & 0x01));
2619 input_report_key(input, BTN_RIGHT,
2620 (report_data->button & 0x02));
2621 input_report_key(input, BTN_MIDDLE,
2622 (report_data->button & 0x04));
2623 input_sync(input);
2624 }
2625
2626 DBGPRINTK(("%s: deltax = %d\n", __func__, report_data->rel_deltaX));
2627 DBGPRINTK(("%s: deltay = %d\n", __func__, report_data->rel_deltaY));
2628 DBGPRINTK(("%s: left_btn = %d\n",
2629 __func__, report_data->button & 0x01));
2630 DBGPRINTK(("%s: right_btn = %d\n",
2631 __func__, report_data->button & 0x02));
2632 DBGPRINTK(("%s: middle_btn = %d\n",
2633 __func__, report_data->button & 0x04));
2634
2635 /* store current active gestures array into
2636 ** prev active gesture array. */
2637 for (i = 0; i < MAX_FINGERS; i++)
2638 touch->prev_active_gestures[i] = touch->cur_active_gestures[i];
2639 touch->prev_touch_fingers = report_data->touch_fingers;
2640
2641 return report_data->gestures_count | report_data->rel_deltaX
2642 |report_data->rel_deltaY | report_data->button;
2643 }
2644
2645 static int cyapa_abs_input_report_data(struct cyapa_i2c *touch,
2646 struct cyapa_report_data *report_data)
2647 {
2648 int i;
2649 int have_data = 0;
2650 struct input_dev *input = touch->input;
2651
2652 DBGPRINTK(("%s: ...\n", __func__));
2653
2654 cyapa_process_prev_gesture_report(touch, report_data);
2655 if (report_data->gestures_count > 0) {
2656 DBGPRINTK(("%s: do gesture report, gestures_count = %d\n",
2657 __func__, report_data->gestures_count));
2658 /* gesture trigged */
2659 for (i = 0; i < report_data->gestures_count; i++) {
2660 cyapa_gesture_report(touch, report_data,
2661 &report_data->gestures[i]);
2662 }
2663 } else if (report_data->touch_fingers) {
2664 /* no gesture trigged, report touchs move data. */
2665 if (report_data->touch_fingers > 1) {
2666 DBGPRINTK(("%s: more then 1 finger touch, \
2667 touch_fingers = %d\n",
2668 __func__, report_data->touch_fingers));
2669 /*
2670 ** two and much more finger on trackpad are used for
2671 ** gesture only, so even no gesture are trigged,
2672 ** do not make cursor move also.
2673 ** Here, must keep on report finger touched, otherwise,
2674 ** when multi-finger touch not in same time will
2675 ** triiged clikc.
2676 */
2677 input_report_key(input, BTN_TOUCH, 1);
2678 input_report_abs(input, ABS_PRESSURE,
2679 report_data->avg_pressure);
2680 input_report_abs(input, ABS_TOOL_WIDTH,
2681 CYAPA_TOOL_WIDTH);
2682 #if GESTURE_MULTI_TOUCH_ONE_CLICK
2683 cyapa_report_fingers(input, report_data->touch_fingers);
2684 #else
2685 cyapa_report_fingers(input, 1);
2686 #endif
2687
2688 touch->prev_abs_x = -1;
2689 touch->prev_abs_y = -1;
2690
2691 input_report_key(input, BTN_LEFT,
2692 report_data->button & 0x01);
2693 input_report_key(input, BTN_RIGHT,
2694 report_data->button & 0x02);
2695 input_report_key(input, BTN_MIDDLE,
2696 report_data->button & 0x04);
2697
2698 input_sync(input);
2699 } else {
2700 DBGPRINTK(("%s: 1 finger touch, make cursor move\n",
2701 __func__));
2702 /* avoid cursor jump, when touched finger changed
2703 ** from multi-touch to one finger touch. */
2704 if (touch->prev_touch_fingers > 1) {
2705 /* cheat system or application that no finger
2706 ** has touched to may them
2707 ** lock the cursor when later only one finger
2708 ** touched on trackpad. */
2709 input_report_key(input, BTN_TOUCH, 0);
2710 input_report_abs(input, ABS_PRESSURE, 0);
2711 input_report_abs(input, ABS_TOOL_WIDTH, 0);
2712 cyapa_report_fingers(input, 0);
2713 touch->prev_abs_x = -1;
2714 touch->prev_abs_y = -1;
2715 input_report_key(input, BTN_LEFT,
2716 report_data->button & 0x01);
2717 input_report_key(input, BTN_RIGHT,
2718 report_data->button & 0x02);
2719 input_report_key(input, BTN_MIDDLE,
2720 report_data->button & 0x04);
2721 input_sync(input);
2722 } else {
2723 /* only 1 finger can make cursor move. */
2724 touch->xy_touchs_included_bits = 0x01;
2725 cyapa_calculate_abs_xy(touch, report_data);
2726
2727 input_report_key(input, BTN_TOUCH, 1);
2728 input_report_abs(input, ABS_X, touch->abs_x);
2729 input_report_abs(input, ABS_Y, touch->abs_y);
2730 input_report_abs(input,
2731 ABS_PRESSURE,
2732 report_data->avg_pressure);
2733 input_report_abs(input, ABS_TOOL_WIDTH,
2734 CYAPA_TOOL_WIDTH);
2735
2736 cyapa_report_fingers(input,
2737 report_data->touch_fingers);
2738
2739 input_report_key(input, BTN_LEFT,
2740 report_data->button & 0x01);
2741 input_report_key(input, BTN_RIGHT,
2742 report_data->button & 0x02);
2743 input_report_key(input, BTN_MIDDLE,
2744 report_data->button & 0x04);
2745
2746 input_sync(input);
2747 }
2748 }
2749 } else {
2750 /*
2751 ** 1. two or more fingers on trackpad are used for gesture only,
2752 ** so even no gesture are trigged, do not make cursor move also.
2753 ** 2. no gesture and no touch on trackpad.
2754 */
2755 DBGPRINTK(("%s: no finger touch.\n", __func__));
2756
2757 input_report_key(input, BTN_TOUCH, 0);
2758 input_report_abs(input, ABS_PRESSURE, 0);
2759 input_report_abs(input, ABS_TOOL_WIDTH, 0);
2760 cyapa_report_fingers(input, 0);
2761
2762 touch->prev_abs_x = -1;
2763 touch->prev_abs_y = -1;
2764
2765 input_report_key(input, BTN_LEFT, report_data->button & 0x01);
2766 input_report_key(input, BTN_RIGHT, report_data->button & 0x02);
2767 input_report_key(input, BTN_MIDDLE, report_data->button & 0x04);
2768
2769 input_sync(input);
2770 }
2771
2772 /* store current active gestures array into
2773 ** prev active gesture array. */
2774 for (i = 0; i < MAX_FINGERS; i++)
2775 touch->prev_active_gestures[i] = touch->cur_active_gestures[i];
2776 touch->prev_touch_fingers = report_data->touch_fingers;
2777
2778 have_data = (report_data->gestures_count +
2779 report_data->touch_fingers + report_data->button);
2780
2781 DBGPRINTK(("%s: gesture count = %d, touch finger =%d, \
2782 button = 0x%02x\n", __func__, report_data->gestures_count,
2783 report_data->touch_fingers, report_data->button));
2784 return have_data;
2785 }
2786
2787 static bool cyapa_i2c_get_input(struct cyapa_i2c *touch)
2788 {
2789 int i;
2790 int ret_read_size = -1;
2791 int read_length = 0;
2792 union cyapa_reg_data reg_data;
2793 struct cyapa_reg_data_gen1 *gen1_data;
2794 struct cyapa_reg_data_gen2 *gen2_data;
2795 struct cyapa_report_data report_data;
2796
2797 DBGPRINTK(("%s: start ...\n", __func__));
2798
2799 memset(&reg_data, 0, sizeof(union cyapa_reg_data));
2800
2801 /* read register data from trackpad. */
2802 gen1_data = &reg_data.gen1_data;
2803 gen2_data = &reg_data.gen2_data;
2804 read_length = CYAPA_REL_REG_DATA_SIZE;
2805 if (touch->platform_data->gen == CYAPA_GEN1)
2806 read_length = (int)sizeof(struct cyapa_reg_data_gen1);
2807 else
2808 read_length = (int)sizeof(struct cyapa_reg_data_gen2);
2809 DBGPRINTK(("%s: read gen%d data, read length=%d\n", __func__,
2810 ((touch->platform_data->gen == CYAPA_GEN1) ? 1 : 2),
2811 read_length));
2812 ret_read_size = cyapa_i2c_reg_read_block(touch->client,
2813 DATA_REG_START_OFFSET,
2814 read_length,
2815 (u8 *)&reg_data);
2816 if (ret_read_size < 0) {
2817 DBGPRINTK(("%s: I2C read data from trackpad error = %d\n",
2818 __func__, ret_read_size));
2819 return 0;
2820 }
2821
2822 if (cyapa_verify_data_device(touch, &reg_data)) {
2823 DBGPRINTK(("%s: verify data device failed, \
2824 invalid data, skip.\n", __func__));
2825 return 0;
2826 }
2827
2828 /* process and parse raw data that read from Trackpad. */
2829 memset(&report_data, 0, sizeof(struct cyapa_report_data));
2830 touch->xy_touchs_included_bits = 0;
2831 /* initialize current active gestures array. */
2832 for (i = 0; i < MAX_FINGERS; i++)
2833 touch->cur_active_gestures[i] = 0;
2834
2835 if (touch->platform_data->gen == CYAPA_GEN1)
2836 cyapa_parse_gen1_data(touch, gen1_data, &report_data);
2837 else
2838 cyapa_parse_gen2_data(touch, gen2_data, &report_data);
2839
2840 /* report data to input subsystem. */
2841 if (touch->platform_data->use_absolute_mode == false)
2842 return cyapa_rel_input_report_data(touch, &report_data);
2843 else
2844 return cyapa_abs_input_report_data(touch, &report_data);
2845 }
2846
2847 static void cyapa_i2c_reschedule_work(struct cyapa_i2c *touch,
2848 unsigned long delay)
2849 {
2850 unsigned long flags;
2851
2852 spin_lock_irqsave(&touch->lock, flags);
2853
2854 /*
2855 * If work is already scheduled then subsequent schedules will not
2856 * change the scheduled time that's why we have to cancel it first.
2857 */
2858 __cancel_delayed_work(&touch->dwork);
2859 schedule_delayed_work(&touch->dwork, delay);
2860
2861 spin_unlock_irqrestore(&touch->lock, flags);
2862 }
2863
2864 static irqreturn_t cyapa_i2c_irq(int irq, void *dev_id)
2865 {
2866 struct cyapa_i2c *touch = dev_id;
2867
2868 DBGPRINTK(("%s: trackpad interrupt captured. \
2869 report_rate=%d; read_pending=%d\n",
2870 __func__, touch->platform_data->report_rate,
2871 touch->read_pending));
2872
2873 if (touch->platform_data->report_rate == 0) {
2874 /*
2875 ** no limitatioin for data reporting.
2876 ** the report rate depending on trackpad max report rate.
2877 ** this is the default report mode.
2878 */
2879 cyapa_i2c_reschedule_work(touch, 0);
2880 } else {
2881 /*
2882 ** when use limited report rate, some important data packages
2883 ** may be lost. Such as a tap or double tap gesture may be lost.
2884 ** So firmware need to keep this data until there data is read.
2885 */
2886 if (!touch->read_pending) {
2887 touch->read_pending = 1;
2888 cyapa_i2c_reschedule_work(touch, touch->scan_ms);
2889 }
2890 }
2891
2892 return IRQ_HANDLED;
2893 }
2894
2895 /* Control the Device polling rate / Work Handler sleep time */
2896 static unsigned long cyapa_i2c_adjust_delay(struct cyapa_i2c *touch,
2897 bool have_data)
2898 {
2899 unsigned long delay, nodata_count_thres;
2900
2901 if (touch->platform_data->use_polling_mode) {
2902 delay = touch->platform_data->polling_interval_time_active;
2903 if (have_data) {
2904 touch->no_data_count = 0;
2905 } else {
2906 nodata_count_thres
2907 = CYAPA_NO_DATA_THRES / touch->scan_ms;
2908 if (touch->no_data_count < nodata_count_thres)
2909 touch->no_data_count++;
2910 else
2911 delay = CYAPA_NO_DATA_SLEEP_MSECS;
2912 }
2913 return msecs_to_jiffies(delay);
2914 } else {
2915 delay = msecs_to_jiffies(CYAPA_THREAD_IRQ_SLEEP_MSECS);
2916 return round_jiffies_relative(delay);
2917 }
2918 }
2919
2920 /* Work Handler */
2921 static void cyapa_i2c_work_handler(struct work_struct *work)
2922 {
2923 bool have_data;
2924 struct cyapa_i2c *touch
2925 = container_of(work, struct cyapa_i2c, dwork.work);
2926 unsigned long delay;
2927
2928 DBGPRINTK(("%s: start ...\n", __func__));
2929
2930 have_data = cyapa_i2c_get_input(touch);
2931
2932 /*
2933 * While interrupt driven, there is no real need to poll the device.
2934 * But touchpads are very sensitive, so there could be errors
2935 * related to physical environment and the attention line isn't
2936 * neccesarily asserted. In such case we can lose the touchpad.
2937 * We poll the device once in CYAPA_THREAD_IRQ_SLEEP_SECS and
2938 * if error is detected, we try to reset and reconfigure the touchpad.
2939 */
2940 delay = cyapa_i2c_adjust_delay(touch, have_data);
2941 /* if needs fixed interval time trackpad scan, open it.
2942 cyapa_i2c_reschedule_work(touch, delay);
2943 */
2944
2945 touch->read_pending = 0;
2946
2947 DBGPRINTK(("%s: done ...\n", __func__));
2948 }
2949
2950 static int cyapa_i2c_open(struct input_dev *input)
2951 {
2952 struct cyapa_i2c *touch = input_get_drvdata(input);
2953 int retval;
2954
2955 if (0 == touch->open_count) {
2956 /* Since input_dev mouse, wheel, and kbd will all use same open
2957 ** and close routines. But indeed, reset config to trackpad
2958 ** once is enought,So when trackpad is open for the first time,
2959 ** reset it. for other time not do it.
2960 */
2961 retval = cyapa_i2c_reset_config(touch);
2962 if (retval) {
2963 DBGPRINTK(("%s: failed to reset i2c trackpad. \
2964 error = %d\n", __func__, retval));
2965 return retval;
2966 }
2967 }
2968 touch->open_count++;
2969
2970 if (touch->platform_data->use_polling_mode) {
2971 /*
2972 ** for the firstly time, it is set to CYAPA_NO_DATA_SLEEP_MSECS,
2973 ** when data is read from trackpad, the read speed will
2974 ** be pull up.
2975 */
2976 cyapa_i2c_reschedule_work(touch,
2977 msecs_to_jiffies(CYAPA_NO_DATA_SLEEP_MSECS));
2978 }
2979
2980 DBGPRINTK(("%s: touch->open_count = %d ...\n",
2981 __func__, touch->open_count));
2982
2983 return 0;
2984 }
2985
2986 static void cyapa_i2c_close(struct input_dev *input)
2987 {
2988 struct cyapa_i2c *touch = input_get_drvdata(input);
2989
2990 touch->open_count--;
2991
2992 if (0 == touch->open_count) {
2993 /* Since input_dev mouse, wheel, and kbd will all use same open
2994 ** and close routines.
2995 ** so when all mouse, wheel and kbd input_dev is closed,
2996 ** then cancel the delayed work routine.
2997 */
2998 cancel_delayed_work_sync(&touch->dwork);
2999 }
3000
3001 DBGPRINTK(("%s: touch->open_count=%d\n", __func__, touch->open_count));
3002 }
3003
3004 static struct cyapa_i2c *cyapa_i2c_touch_create(struct i2c_client *client)
3005 {
3006 struct cyapa_i2c *touch;
3007
3008 touch = kzalloc(sizeof(struct cyapa_i2c), GFP_KERNEL);
3009 if (!touch)
3010 return NULL;
3011
3012 DBGPRINTK(("%s: client=0x%p, allocate memory for touch successfully.\n",
3013 __func__, client));
3014
3015 touch->platform_data = &cyapa_i2c_platform_data;
3016 if (client->dev.platform_data) {
3017 DBGPRINTK(("%s: client->dev.platform_data is set, copy it.\n",
3018 __func__));
3019 *touch->platform_data
3020 = *(struct cyapa_platform_data *)
3021 client->dev.platform_data;
3022 }
3023
3024 cyapa_print_paltform_data(__func__, touch->platform_data);
3025
3026 if (touch->platform_data->use_polling_mode &&
3027 (touch->platform_data->report_rate == 0)) {
3028 /* when user miss setting platform data,
3029 ** ensure that system is robust.
3030 ** no divid zero error. */
3031 touch->platform_data->report_rate
3032 = CYAPA_POLLING_REPORTRATE_DEFAULT;
3033 }
3034 touch->scan_ms = touch->platform_data->report_rate
3035 ? (1000 / touch->platform_data->report_rate) : 0;
3036 touch->open_count = 0;
3037 touch->prev_abs_x = -1;
3038 touch->prev_abs_y = -1;
3039 touch->client = client;
3040 touch->zoomin_delta = 0;
3041 touch->zoomout_delta = 0;
3042 touch->hscroll_left = 0;
3043 touch->hscroll_right = 0;
3044 touch->prev_touch_fingers = 0;
3045
3046 cyapa_set_preferences(touch);
3047 cyapa_reset_cursor_filters_data(touch);
3048
3049 INIT_DELAYED_WORK(&touch->dwork, cyapa_i2c_work_handler);
3050 spin_lock_init(&touch->lock);
3051
3052 return touch;
3053 }
3054
3055 static int cyapa_create_input_dev_mouse(struct cyapa_i2c *touch)
3056 {
3057 int retval = 0;
3058 struct input_dev *input = NULL;
3059
3060 input = touch->input = input_allocate_device();
3061 if (!touch->input) {
3062 dev_err(&touch->client->dev,
3063 "%s: Allocate memory for Input device failed: %d\n",
3064 __func__, retval);
3065 return -ENOMEM;
3066 }
3067
3068 input->name = "cyapa_i2c_trackpad";
3069 input->phys = touch->client->adapter->name;
3070 input->id.bustype = BUS_I2C;
3071 input->id.version = 1;
3072 input->dev.parent = &touch->client->dev;
3073
3074 input->open = cyapa_i2c_open;
3075 input->close = cyapa_i2c_close;
3076 input_set_drvdata(input, touch);
3077
3078 if (touch->platform_data->use_absolute_mode) {
3079 /* absolution data report mode. */
3080 __set_bit(EV_ABS, input->evbit);
3081 __set_bit(EV_KEY, input->evbit);
3082
3083 input_set_abs_params(input, ABS_X, 0,
3084 touch->max_absolution_x, 0, 0);
3085 input_set_abs_params(input, ABS_Y, 0,
3086 touch->max_absolution_y, 0, 0);
3087 input_set_abs_params(input, ABS_PRESSURE, 0, 255, 0, 0);
3088 input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
3089
3090 __set_bit(BTN_TOUCH, input->keybit);
3091 __set_bit(BTN_TOOL_FINGER, input->keybit);
3092 __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
3093 __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
3094 __set_bit(BTN_TOOL_QUADTAP, input->keybit);
3095
3096 __set_bit(BTN_LEFT, input->keybit);
3097 __set_bit(BTN_RIGHT, input->keybit);
3098 __set_bit(BTN_MIDDLE, input->keybit);
3099
3100 __clear_bit(EV_REL, input->evbit);
3101 __clear_bit(REL_X, input->relbit);
3102 __clear_bit(REL_Y, input->relbit);
3103 __clear_bit(BTN_TRIGGER, input->keybit);
3104
3105 input_abs_set_res(input,
3106 ABS_X,
3107 touch->max_absolution_x/touch->physical_size_x);
3108 input_abs_set_res(input,
3109 ABS_Y,
3110 touch->max_absolution_y/touch->physical_size_y);
3111
3112 DBGPRINTK(("%s: Use absolute data reporting mode.\n",
3113 __func__));
3114 } else {
3115 /* relative data reporting mode. */
3116 __set_bit(EV_REL, input->evbit);
3117 __set_bit(REL_X, input->relbit);
3118 __set_bit(REL_Y, input->relbit);
3119
3120 __set_bit(EV_KEY, input->evbit);
3121 __set_bit(BTN_LEFT, input->keybit);
3122 __set_bit(BTN_RIGHT, input->keybit);
3123 __set_bit(BTN_MIDDLE, input->keybit);
3124
3125 __clear_bit(EV_ABS, input->evbit);
3126
3127 DBGPRINTK(("%s: Use relative data reporting mode.\n",
3128 __func__));
3129 }
3130
3131 /* Register the device in input subsystem */
3132 retval = input_register_device(touch->input);
3133 if (retval) {
3134 dev_err(&touch->client->dev,
3135 "%s: Input device register failed: %d\n",
3136 __func__, retval);
3137
3138 input_free_device(input);
3139 return retval;
3140 }
3141
3142 return 0;
3143 }
3144
3145 static int cyapa_create_input_dev_wheel(struct cyapa_i2c *touch)
3146 {
3147 int retval = 0;
3148 struct input_dev *input_wheel = NULL;
3149
3150 input_wheel = touch->input_wheel = input_allocate_device();
3151 if (!touch->input_wheel) {
3152 dev_err(&touch->client->dev,
3153 "%s: Allocate memory for Input device failed: %d\n",
3154 __func__, retval);
3155 return -ENOMEM;
3156 }
3157
3158 input_wheel->name = "cyapa_i2c_wheel";
3159 input_wheel->phys = touch->client->adapter->name;
3160 input_wheel->id.bustype = BUS_I2C;
3161 input_wheel->id.version = 1;
3162 input_wheel->dev.parent = &touch->client->dev;
3163 input_wheel->open = cyapa_i2c_open;
3164 input_wheel->close = cyapa_i2c_close;
3165 input_set_drvdata(input_wheel, touch);
3166
3167 __set_bit(EV_KEY, input_wheel->evbit);
3168 __set_bit(EV_REL, input_wheel->evbit);
3169 __set_bit(REL_WHEEL, input_wheel->relbit);
3170
3171 retval = input_register_device(touch->input_wheel);
3172 if (retval) {
3173 dev_err(&touch->client->dev,
3174 "%s: Input device register failed: %d\n",
3175 __func__, retval);
3176
3177 input_free_device(input_wheel);
3178 return retval;
3179 }
3180
3181 return 0;
3182 }
3183
3184 #define MAX_NR_SCANCODES 128
3185
3186 static unsigned char cyapa_virtual_keycode[MAX_NR_SCANCODES] = {
3187 /* Bellow keys are supported.
3188 KEY_ENTER 28
3189 KEY_LEFTCTRL 29
3190 KEY_LEFTSHIFT 42
3191 KEY_RIGHTSHIFT 54
3192 KEY_LEFTALT 56
3193 KEY_KPMINUS 74
3194 KEY_KPPLUS 78
3195 KEY_RIGHTCTRL 97
3196 KEY_RIGHTALT 100
3197 KEY_HOME 102
3198 KEY_UP 103
3199 KEY_PAGEUP 104
3200 KEY_LEFT 105
3201 KEY_RIGHT 106
3202 KEY_END 107
3203 KEY_DOWN 108
3204 KEY_PAGEDOWN 109
3205 */
3206 28, 29, 42, 54, 56, 74, 78, 97, 100,
3207 102, 103, 104, 105, 106, 107, 108, 109
3208 };
3209
3210 static int cyapa_create_input_dev_kbd(struct cyapa_i2c *touch)
3211 {
3212 int retval = 0;
3213 int i;
3214 struct input_dev *input_kbd = NULL;
3215
3216 input_kbd = touch->input_kbd = input_allocate_device();
3217 if (!touch->input_kbd) {
3218 dev_err(&touch->client->dev,
3219 "%s: Allocate memory for Input device failed: %d\n",
3220 __func__, retval);
3221 return -ENOMEM;
3222 }
3223
3224 input_kbd->name = "cyapa_i2c_virtual_kbd";
3225 input_kbd->phys = touch->client->adapter->name;
3226 input_kbd->id.bustype = BUS_I2C;
3227 input_kbd->id.version = 1;
3228 input_kbd->dev.parent = &touch->client->dev;
3229 input_kbd->open = cyapa_i2c_open;
3230 input_kbd->close = cyapa_i2c_close;
3231 input_set_drvdata(input_kbd, touch);
3232
3233 input_kbd->keycode = &cyapa_virtual_keycode;
3234 input_kbd->keycodesize = sizeof(unsigned char);
3235 input_kbd->keycodemax = ARRAY_SIZE(cyapa_virtual_keycode);
3236
3237 __set_bit(EV_KEY, input_kbd->evbit);
3238 __set_bit(EV_REP, input_kbd->evbit);
3239
3240 for (i = 0; i < ARRAY_SIZE(cyapa_virtual_keycode); i++)
3241 __set_bit(cyapa_virtual_keycode[i], input_kbd->keybit);
3242 __clear_bit(KEY_RESERVED, input_kbd->keybit);
3243
3244 retval = input_register_device(touch->input_kbd);
3245 if (retval) {
3246 dev_err(&touch->client->dev,
3247 "%s: Input device register failed: %d\n",
3248 __func__, retval);
3249
3250 input_free_device(input_kbd);
3251 return retval;
3252 }
3253
3254 return 0;
3255 }
3256
3257 static int __devinit cyapa_i2c_probe(struct i2c_client *client,
3258 const struct i2c_device_id *dev_id)
3259 {
3260 int retval = 0;
3261 struct cyapa_i2c *touch;
3262
3263 DBGPRINTK(("%s: start ...\n", __func__));
3264 touch = cyapa_i2c_touch_create(client);
3265 if (!touch)
3266 return -ENOMEM;
3267
3268 /* do platfrom initialize firstly. */
3269 if (touch->platform_data->init)
3270 retval = touch->platform_data->init();
3271 if (retval)
3272 goto err_mem_free;
3273
3274 /* set irq number if not using polling mode. */
3275 if (touch->platform_data->use_polling_mode == true) {
3276 touch->irq = -1;
3277 } else {
3278 if (touch->platform_data->irq_gpio == -1) {
3279 if (client->irq) {
3280 touch->irq = client->irq;
3281 } else {
3282 /* irq mode is not supported by system. */
3283 touch->platform_data->use_polling_mode = true;
3284 touch->irq = -1;
3285 }
3286 } else {
3287 touch->irq
3288 = gpio_to_irq(touch->platform_data->irq_gpio);
3289 }
3290 }
3291 DBGPRINTK(("%s: irq=%d, client->irq=%d\n",
3292 __func__, touch->irq, client->irq));
3293
3294 if (touch->platform_data->use_polling_mode == false) {
3295 DBGPRINTK(("%s: request interrupt riq.\n", __func__));
3296
3297 set_irq_type(touch->irq, IRQF_TRIGGER_FALLING);
3298 retval = request_irq(touch->irq,
3299 cyapa_i2c_irq,
3300 0,
3301 CYAPA_I2C_NAME,
3302 touch);
3303 if (retval) {
3304 dev_warn(&touch->client->dev,
3305 "%s: IRQ request failed: \
3306 %d, falling back to polling mode.\n",
3307 __func__, retval);
3308
3309 touch->platform_data->use_polling_mode = true;
3310 }
3311 }
3312
3313 /* reconfig trackpad depending on platfrom setting. */
3314 /* Should disable interrupt to protect this polling read operation.
3315 ** Ohterwise, this I2C read will be interrupt by other reading,
3316 ** and failed. */
3317 disable_irq(touch->irq);
3318 cyapa_i2c_reconfig(touch);
3319 enable_irq(touch->irq);
3320
3321 /* create an input_dev instance for virtual mouse trackpad. */
3322 retval = cyapa_create_input_dev_mouse(touch);
3323 if (retval) {
3324 DBGPRINTK(("%s: create mouse input_dev instance filed.\n",
3325 __func__));
3326 goto err_mem_free;
3327 }
3328
3329 /* create an input_dev instances for virtual wheel device
3330 ** and virtual keyboard device. */
3331 retval = cyapa_create_input_dev_wheel(touch);
3332 if (retval) {
3333 DBGPRINTK(("%s: create input_dev instance for wheel filed.\n",
3334 __func__));
3335 goto err_mem_free;
3336 }
3337
3338 retval = cyapa_create_input_dev_kbd(touch);
3339 if (retval) {
3340 DBGPRINTK(("%s: create keyboad input_dev instance filed.\n",
3341 __func__));
3342 goto err_mem_free;
3343 }
3344
3345 i2c_set_clientdata(client, touch);
3346
3347 DBGPRINTK(("%s: Done successfully.\n", __func__));
3348
3349 return 0;
3350
3351 err_mem_free:
3352 /* release previous allocated input_dev instances. */
3353 if (touch->input) {
3354 input_free_device(touch->input);
3355 touch->input = NULL;
3356 }
3357
3358 if (touch->input_wheel) {
3359 input_free_device(touch->input_wheel);
3360 touch->input_wheel = NULL;
3361 }
3362
3363 if (touch->input_kbd) {
3364 input_free_device(touch->input_kbd);
3365 touch->input_kbd = NULL;
3366 }
3367
3368 kfree(touch);
3369
3370 DBGPRINTK(("%s: exist with error %d.\n", __func__, retval));
3371 return retval;
3372 }
3373
3374 static int __devexit cyapa_i2c_remove(struct i2c_client *client)
3375 {
3376 struct cyapa_i2c *touch = i2c_get_clientdata(client);
3377
3378 if (!touch->platform_data->use_polling_mode)
3379 free_irq(client->irq, touch);
3380
3381 if (touch->input)
3382 input_unregister_device(touch->input);
3383 if (touch->input_wheel)
3384 input_unregister_device(touch->input);
3385 if (touch->input_kbd)
3386 input_unregister_device(touch->input);
3387 kfree(touch);
3388
3389 DBGPRINTK(("%s: ...\n", __func__));
3390
3391 return 0;
3392 }
3393
3394 #ifdef CONFIG_PM
3395 static int cyapa_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
3396 {
3397 struct cyapa_i2c *touch = i2c_get_clientdata(client);
3398
3399 DBGPRINTK(("%s: ...\n", __func__));
3400 cancel_delayed_work_sync(&touch->dwork);
3401
3402 return 0;
3403 }
3404
3405 static int cyapa_i2c_resume(struct i2c_client *client)
3406 {
3407 int ret;
3408 struct cyapa_i2c *touch = i2c_get_clientdata(client);
3409
3410 ret = cyapa_i2c_reset_config(touch);
3411 DBGPRINTK(("%s: ...\n", __func__));
3412 if (ret)
3413 return ret;
3414
3415 cyapa_i2c_reschedule_work(touch,
3416 msecs_to_jiffies(CYAPA_NO_DATA_SLEEP_MSECS));
3417
3418 return 0;
3419 }
3420 #else
3421 #define cyapa_i2c_suspend NULL
3422 #define cyapa_i2c_resume NULL
3423 #endif
3424
3425 static const struct i2c_device_id cypress_i2c_id_table[] = {
3426 { CYAPA_I2C_NAME, 0 },
3427 { },
3428 };
3429 MODULE_DEVICE_TABLE(i2c, cypress_i2c_id_table);
3430
3431 static struct i2c_driver cypress_i2c_driver = {
3432 .driver = {
3433 .name = CYAPA_I2C_NAME,
3434 .owner = THIS_MODULE,
3435 },
3436
3437 .probe = cyapa_i2c_probe,
3438 .remove = __devexit_p(cyapa_i2c_remove),
3439
3440 .suspend = cyapa_i2c_suspend,
3441 .resume = cyapa_i2c_resume,
3442 .id_table = cypress_i2c_id_table,
3443 };
3444
3445 static int __init cyapa_i2c_init(void)
3446 {
3447 DBGPRINTK(("%s: start ...\n", __func__));
3448 return i2c_add_driver(&cypress_i2c_driver);
3449 }
3450
3451 static void __exit cyapa_i2c_exit(void)
3452 {
3453 DBGPRINTK(("%s: exit ...\n", __func__));
3454 i2c_del_driver(&cypress_i2c_driver);
3455 }
3456
3457 module_init(cyapa_i2c_init);
3458 module_exit(cyapa_i2c_exit);
3459
3460 MODULE_DESCRIPTION("Cypress I2C Trackpad Driver");
3461 MODULE_AUTHOR("Dudley Du <dudl@cypress.com>");
3462 MODULE_LICENSE("GPL");
3463
OLDNEW
« no previous file with comments | « drivers/input/mouse/Makefile ('k') | include/linux/cyapa.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698