OLD | NEW |
(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 = ®_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 = ®_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(®_data, 0, sizeof(union cyapa_reg_data)); |
| 2800 |
| 2801 /* read register data from trackpad. */ |
| 2802 gen1_data = ®_data.gen1_data; |
| 2803 gen2_data = ®_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 *)®_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, ®_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 |
OLD | NEW |