experices on a linux touchscreen panel driver

"Write a good touch feel touchscreen panel driver"

Recently, I had re-factory three time of our touch panel driver.Every time re-factory with clear aim.

 

Our product use a resistance touchscreen panel(about touchscreen panel, see [http://en.wikipedia.org/wiki/Touchscreen]), the touch screen use an adc(Analog-to-digital converter) convert the resistance change to the digital number, then these value should be calibration by algorithm like (tslib, [http://tslib.berlios.de/]) does. After that, these value is be a human readable coordinate. The event should report we user touch the touchscreen, and should report a touch up event notice service layer the user leave the touchscreen. 

In linux, all of these use by api in (linux/input.h), such as : 

input_report_abs();

input_event();

input_sync();

Our first version of driver using a kthread, a infinite while loop;

void kthread_func() {
        while(1) {
                poll_event(x, y, touch); //get a event from adc driver.
                input_report_abs(x);    //here report the coordinate of touch event
                input_event(touch);     //here report the state of touch, 1
                                        //means touch down, 0 means touch up.
                input_sync();                   //sync means a complete event.
                sleep(delay);
        }
}

This design is very simple and clear, But it have some shortcoming.

1. the kthread is hard to control, it hard stop by the other thread, until it stop by itself. It will be problem we you want to suspend/resume driver. 

2. There is a touchscreen use case, If you move quickly you finger on the touchscreen, maybe there is one or two event is touch leave the screen in the middle of this move. This should be ignore by   driver. Excellent product like iPad, iPhone touchscreen have this feather. But in this implantation, the touch leave event will report.

The next version of this driver, we change few things.

1. use a single_threaded_workqueue instead of kthread, so we can stop the thread when the driver suspend.

2. in the workquque, it only report the down event and the abs change of the toucscreen, the touch up event is sent by a hrtimer.  every time the work is running, it will adjust the timer. If there is no event coming, the timer is not modify by anyone, so it expired, the callback is called, it will send a touch up event. 

pseudocode is:

   timer_func()
   {
        input_report_abs(ABS_X, x);     //x,y coordinate
        input_report_abs(ABS_Y, y);
        input_report_abs(ABS_PRESSURE, 0); //pressure
        input_event(EV_KEY, BTN_TOUCH, 0); //touch up event
        input_sync();
   }

   workqueue_func()
   {

        poll_event(x, y, touch); //get a event from adc driver.
        start_hrtimer(timer, timeout_of_touch_up); //normally 2-10
                                                   //times of delay
        if (touch) {
                input_report_abs(x);    //here report the coordinate of touch event
                input_event(touch);     //here report the state of touch, 1
                                        //means touch down, 0 means touch up.
                input_sync();                   //sync means a complete event.
        }
        queue_self_to_delayed_workqueue(delay);
    }

In this implemention, above all issues are fixed.

1. use a delayed workqueue, we can cancel the queued work to stop the wokequeue looping. It is very easy to control.

2. if there is one or two event up in the figer move(figer gesture), the timeout will not expired, so the move is continue until user really want to leave their figure off the touchscreen.

I'm very happen that our touchscreen have a better touch feelling like the top level of the industry such as iPad. :)