diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2011-05-17 02:17:40 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-05-17 02:20:17 -0400 |
commit | f1e430e6369f5edac552d99bff15369ef8c6bbd2 (patch) | |
tree | 878ff70b8fd431e25b7cba736cd08ca367936582 | |
parent | 3532cb0ca2774b05e3c660f536ba3d1b38061fc9 (diff) |
Input: ad714x - fix captouch wheel option algorithm
As reported by Jean-Francois Dagenais, the wheel algorithm caused a
divide by zero exception due to missing variable pre-initialization.
In fact it turned out that the whole algorithm had several problems.
It is therefore replaced with something that is known working.
Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Tested-by: Jean-Francois Dagenais <jeff.dagenais@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/misc/ad714x.c | 109 |
1 files changed, 19 insertions, 90 deletions
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index 5f683ec2999e..c3a62c42cd28 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c | |||
@@ -79,13 +79,7 @@ struct ad714x_slider_drv { | |||
79 | struct ad714x_wheel_drv { | 79 | struct ad714x_wheel_drv { |
80 | int abs_pos; | 80 | int abs_pos; |
81 | int flt_pos; | 81 | int flt_pos; |
82 | int pre_mean_value; | ||
83 | int pre_highest_stage; | 82 | int pre_highest_stage; |
84 | int pre_mean_value_no_offset; | ||
85 | int mean_value; | ||
86 | int mean_value_no_offset; | ||
87 | int pos_offset; | ||
88 | int pos_ratio; | ||
89 | int highest_stage; | 83 | int highest_stage; |
90 | enum ad714x_device_state state; | 84 | enum ad714x_device_state state; |
91 | struct input_dev *input; | 85 | struct input_dev *input; |
@@ -404,7 +398,6 @@ static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx) | |||
404 | ad714x_slider_cal_highest_stage(ad714x, idx); | 398 | ad714x_slider_cal_highest_stage(ad714x, idx); |
405 | ad714x_slider_cal_abs_pos(ad714x, idx); | 399 | ad714x_slider_cal_abs_pos(ad714x, idx); |
406 | ad714x_slider_cal_flt_pos(ad714x, idx); | 400 | ad714x_slider_cal_flt_pos(ad714x, idx); |
407 | |||
408 | input_report_abs(sw->input, ABS_X, sw->flt_pos); | 401 | input_report_abs(sw->input, ABS_X, sw->flt_pos); |
409 | input_report_key(sw->input, BTN_TOUCH, 1); | 402 | input_report_key(sw->input, BTN_TOUCH, 1); |
410 | } else { | 403 | } else { |
@@ -468,104 +461,41 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx) | |||
468 | /* | 461 | /* |
469 | * When the scroll wheel is activated, we compute the absolute position based | 462 | * When the scroll wheel is activated, we compute the absolute position based |
470 | * on the sensor values. To calculate the position, we first determine the | 463 | * on the sensor values. To calculate the position, we first determine the |
471 | * sensor that has the greatest response among the 8 sensors that constitutes | 464 | * sensor that has the greatest response among the sensors that constitutes |
472 | * the scrollwheel. Then we determined the 2 sensors on either sides of the | 465 | * the scrollwheel. Then we determined the sensors on either sides of the |
473 | * sensor with the highest response and we apply weights to these sensors. The | 466 | * sensor with the highest response and we apply weights to these sensors. The |
474 | * result of this computation gives us the mean value which defined by the | 467 | * result of this computation gives us the mean value. |
475 | * following formula: | ||
476 | * For i= second_before_highest_stage to i= second_after_highest_stage | ||
477 | * v += Sensor response(i)*WEIGHT*(i+3) | ||
478 | * w += Sensor response(i) | ||
479 | * Mean_Value=v/w | ||
480 | * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio | ||
481 | */ | 468 | */ |
482 | 469 | ||
483 | #define WEIGHT_FACTOR 30 | ||
484 | /* This constant prevents the "PositionOffset" from reaching a big value */ | ||
485 | #define OFFSET_POSITION_CLAMP 120 | ||
486 | static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx) | 470 | static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx) |
487 | { | 471 | { |
488 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | 472 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; |
489 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | 473 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; |
490 | int stage_num = hw->end_stage - hw->start_stage + 1; | 474 | int stage_num = hw->end_stage - hw->start_stage + 1; |
491 | int second_before, first_before, highest, first_after, second_after; | 475 | int first_before, highest, first_after; |
492 | int a_param, b_param; | 476 | int a_param, b_param; |
493 | 477 | ||
494 | /* Calculate Mean value */ | ||
495 | |||
496 | second_before = (sw->highest_stage + stage_num - 2) % stage_num; | ||
497 | first_before = (sw->highest_stage + stage_num - 1) % stage_num; | 478 | first_before = (sw->highest_stage + stage_num - 1) % stage_num; |
498 | highest = sw->highest_stage; | 479 | highest = sw->highest_stage; |
499 | first_after = (sw->highest_stage + stage_num + 1) % stage_num; | 480 | first_after = (sw->highest_stage + stage_num + 1) % stage_num; |
500 | second_after = (sw->highest_stage + stage_num + 2) % stage_num; | ||
501 | |||
502 | if (((sw->highest_stage - hw->start_stage) > 1) && | ||
503 | ((hw->end_stage - sw->highest_stage) > 1)) { | ||
504 | a_param = ad714x->sensor_val[second_before] * | ||
505 | (second_before - hw->start_stage + 3) + | ||
506 | ad714x->sensor_val[first_before] * | ||
507 | (second_before - hw->start_stage + 3) + | ||
508 | ad714x->sensor_val[highest] * | ||
509 | (second_before - hw->start_stage + 3) + | ||
510 | ad714x->sensor_val[first_after] * | ||
511 | (first_after - hw->start_stage + 3) + | ||
512 | ad714x->sensor_val[second_after] * | ||
513 | (second_after - hw->start_stage + 3); | ||
514 | } else { | ||
515 | a_param = ad714x->sensor_val[second_before] * | ||
516 | (second_before - hw->start_stage + 1) + | ||
517 | ad714x->sensor_val[first_before] * | ||
518 | (second_before - hw->start_stage + 2) + | ||
519 | ad714x->sensor_val[highest] * | ||
520 | (second_before - hw->start_stage + 3) + | ||
521 | ad714x->sensor_val[first_after] * | ||
522 | (first_after - hw->start_stage + 4) + | ||
523 | ad714x->sensor_val[second_after] * | ||
524 | (second_after - hw->start_stage + 5); | ||
525 | } | ||
526 | a_param *= WEIGHT_FACTOR; | ||
527 | 481 | ||
528 | b_param = ad714x->sensor_val[second_before] + | 482 | a_param = ad714x->sensor_val[highest] * |
483 | (highest - hw->start_stage) + | ||
484 | ad714x->sensor_val[first_before] * | ||
485 | (highest - hw->start_stage - 1) + | ||
486 | ad714x->sensor_val[first_after] * | ||
487 | (highest - hw->start_stage + 1); | ||
488 | b_param = ad714x->sensor_val[highest] + | ||
529 | ad714x->sensor_val[first_before] + | 489 | ad714x->sensor_val[first_before] + |
530 | ad714x->sensor_val[highest] + | 490 | ad714x->sensor_val[first_after]; |
531 | ad714x->sensor_val[first_after] + | 491 | |
532 | ad714x->sensor_val[second_after]; | 492 | sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) * |
533 | 493 | a_param) / b_param; | |
534 | sw->pre_mean_value = sw->mean_value; | 494 | |
535 | sw->mean_value = a_param / b_param; | ||
536 | |||
537 | /* Calculate the offset */ | ||
538 | |||
539 | if ((sw->pre_highest_stage == hw->end_stage) && | ||
540 | (sw->highest_stage == hw->start_stage)) | ||
541 | sw->pos_offset = sw->mean_value; | ||
542 | else if ((sw->pre_highest_stage == hw->start_stage) && | ||
543 | (sw->highest_stage == hw->end_stage)) | ||
544 | sw->pos_offset = sw->pre_mean_value; | ||
545 | |||
546 | if (sw->pos_offset > OFFSET_POSITION_CLAMP) | ||
547 | sw->pos_offset = OFFSET_POSITION_CLAMP; | ||
548 | |||
549 | /* Calculate the mean value without the offset */ | ||
550 | |||
551 | sw->pre_mean_value_no_offset = sw->mean_value_no_offset; | ||
552 | sw->mean_value_no_offset = sw->mean_value - sw->pos_offset; | ||
553 | if (sw->mean_value_no_offset < 0) | ||
554 | sw->mean_value_no_offset = 0; | ||
555 | |||
556 | /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */ | ||
557 | |||
558 | if ((sw->pre_highest_stage == hw->end_stage) && | ||
559 | (sw->highest_stage == hw->start_stage)) | ||
560 | sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) / | ||
561 | hw->max_coord; | ||
562 | else if ((sw->pre_highest_stage == hw->start_stage) && | ||
563 | (sw->highest_stage == hw->end_stage)) | ||
564 | sw->pos_ratio = (sw->mean_value_no_offset * 100) / | ||
565 | hw->max_coord; | ||
566 | sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio; | ||
567 | if (sw->abs_pos > hw->max_coord) | 495 | if (sw->abs_pos > hw->max_coord) |
568 | sw->abs_pos = hw->max_coord; | 496 | sw->abs_pos = hw->max_coord; |
497 | else if (sw->abs_pos < 0) | ||
498 | sw->abs_pos = 0; | ||
569 | } | 499 | } |
570 | 500 | ||
571 | static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx) | 501 | static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx) |
@@ -639,9 +569,8 @@ static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx) | |||
639 | ad714x_wheel_cal_highest_stage(ad714x, idx); | 569 | ad714x_wheel_cal_highest_stage(ad714x, idx); |
640 | ad714x_wheel_cal_abs_pos(ad714x, idx); | 570 | ad714x_wheel_cal_abs_pos(ad714x, idx); |
641 | ad714x_wheel_cal_flt_pos(ad714x, idx); | 571 | ad714x_wheel_cal_flt_pos(ad714x, idx); |
642 | |||
643 | input_report_abs(sw->input, ABS_WHEEL, | 572 | input_report_abs(sw->input, ABS_WHEEL, |
644 | sw->abs_pos); | 573 | sw->flt_pos); |
645 | input_report_key(sw->input, BTN_TOUCH, 1); | 574 | input_report_key(sw->input, BTN_TOUCH, 1); |
646 | } else { | 575 | } else { |
647 | /* When the user lifts off the sensor, configure | 576 | /* When the user lifts off the sensor, configure |