Synaptics Touchpad

The Synaptics Touchpad is a pointing device, found on many laptops for instance. First, we discuss the problems with the current driver. Then we talk about a replacement driver to improve the quality and extend features.

Current driver in RELENG_7

Support for this device is already included in FreeBSD and can be enabled with the hw.psm.synaptics_support tunable. Without this, the touchpad is recognized as a standard 3-buttons mouse.

The current implementation provides the following features:

However it lacks several useful features:

An X.Org driver providing some of the missing features is available in the Ports tree but it requires further setup and its features are obviously unavailable for the console.

New driver

The development of the new driver will go through two phases:

  1. Bring the quality of the movement smoothing and tap-hold support on par with what is done internaly by the touchpad, when hw.psm.synaptics_support is not set.

  2. Add more features such as virtual scrolling.

Patch

The latest patch was committed to 8-CURRENT as revision r183888 on 10/14/2008. If you're using CVS or CVSup, check that src/sys/dev/atkbdc/psm.c as revision 1.100.

To be able to use horizontal scrolling with this new driver under X.Org (through sysmouse), you'll need a patch against xf86-input-mouse.

To apply it:

# cd /usr/ports/x11-drivers/xf86-input-mouse
# make patch
# cd work
# patch -p1 < xf86-input-mouse-sysmouse-horizontal-scrolling.patch
# cd ..
# make

Current features

How to use it

You must add the following line in /boot/loader.conf to enable the psm(4) Synaptics support.

hw.psm.synaptics_support="1"

You'll need moused(8) too. Add this to /etc/rc.conf:

moused_enable="YES"

To use it with X.Org, you'll have to disable Synaptics X.Org specific driver and configure a sysmouse mouse. Here's an example to add to /etc/X11/xorg.conf:

Section "InputDevice"
    Identifier      "Mouse0"
    Driver          "mouse"
    Option          "Protocol"      "auto"
    Option          "Device"        "/dev/sysmouse"
    Option          "ZAxisMapping"  "4 5 6 7"
EndSection

Horizontal scrolling is disabled by default. To enable it, you need to set a sysctl (in your /etc/sysctl.conf):

hw.psm.synaptics.vscroll_hor_area=1300

sysctl documentation

Palm detection

Finger pressure

hw.psm.synaptics.min_pressure: 16
hw.psm.synaptics.max_pressure: 220

If the pressure is less than min_pressure of above max_pressure, the packet is ignored but the current action isn't terminated. The pressure is comprised between 0 and 255. Here are some meaningful values, as stated by Synaptics specifications:

Finger width

hw.psm.synaptics.max_width: 10

If the finger width is above max_width, the packet is ignored but the current action isn't terminated. The width is comprised between 4 and 15. Here are some meningful values, as stated by Synaptics specifications:

Movement smoothing

To smooth the movement, we use a weighted average then a division where both the weight and the divisor vary, depending on the movement speed. See "How it works".

hw.psm.synaptics.weight_current: 3
hw.psm.synaptics.weight_previous: 6
hw.psm.synaptics.weight_previous_na: 20
hw.psm.synaptics.weight_len_squared: 2000

weight_current and weight_previous define the range of weights to use when calculating the average. weight_previous_na is used instead of weight_previous when the finger is inside the noisy area (see "Touchpad borders").

TODO: explain weight_len_squared.

hw.psm.synaptics.div_min: 9
hw.psm.synaptics.div_max: 17
hw.psm.synaptics.div_max_na: 30
hw.psm.synaptics.div_len: 100

div_min and div_max define the range of divisors to when calculating the final delta for x & y. div_max_na is used instead of div_max when the finger is inside the noisy area (see "Touchpad borders").

TODO: explain div_len.

hw.psm.synaptics.multiplicator: 10000

This multiplicator is used during averages and divisions to increase the precision.

Touchpad borders

The touchpad borders generate a lot of noise in the reported coordinates. There are two sets of sysctl to control this area.

hw.psm.synaptics.margin_top: 200
hw.psm.synaptics.margin_right: 200
hw.psm.synaptics.margin_bottom: 200
hw.psm.synaptics.margin_left: 200

These margins act as a high-pass filter: for instance, the point [50; 170] will be reported as [200;200].

hw.psm.synaptics.na_top: 1783
hw.psm.synaptics.na_right: 563
hw.psm.synaptics.na_bottom: 1408
hw.psm.synaptics.na_left: 1600

na stands for noisy area. Movements inside these larger margins will be smoothed using different max weight and divisor. See "Movement smoothing".

Points history

hw.psm.synaptics.window_min: 4
hw.psm.synaptics.window_max: 10

window_min indicates the minimum number of packets to receive before an action is considered to be real and wanted. window_max is the maximum number of packets to use in calculations.

Tap and tap-hold

hw.psm.synaptics.tap_max_delta: 80
hw.psm.synaptics.tap_min_queue: 2

tap_max_delta is the maximum delta between points to treat the action as a tap. This is to prevent any unwanted click. tap_min_queue is the minimum number of packets needed to consider a tap.

hw.psm.synaptics.taphold_timeout: 125000

taphold_timeout is the time (in microseconds) between two taps to consider a tap-hols action.

Virtual scrolling

hw.psm.synaptics.vscroll_hor_area: 1300
hw.psm.synaptics.vscroll_ver_area: -600
hw.psm.synaptics.vscroll_min_delta: 50
hw.psm.synaptics.vscroll_div_min: 100
hw.psm.synaptics.vscroll_div_max: 150

An area must be dedicated to virtual scrolling for now. This area is defined by vscroll_hor_area (positive for an area at the bottom, negative for an area at the top) for horizontal scrolling and vscroll_ver_area (positive for an area on the left, negative for an area on the right) for vertical scrolling. vscroll_min_delta is the minimum delta between points to consider a scrolling action. This is to prevent unwanted scrolling when tapping for instance. vscroll_div_min and vscroll_div_max are the divisors used instead of div_min and div_max respectively.

How it works

Movement smoothing and tap-hold support

The smoothing is based on a weighted average:

   1 average = (weight_current * delta + weight_previous * average) / (weight_current + weight_preivous)

where :

This average is calculated for each axis (x & y) separately.

The problem with a simple weighted average as above is that the user has to choose between a smooth but laggy movement (weight_previous greater then weight_current) or a sharp but imprecise movement at slow speed (weight_previous smaller or equal to weight_current).

The idea is then to change weight_previous based on the last packets:

Internaly, the driver keeps the last 10 packets. Here is the simplified algorithm:

   1 dx = abs(new_x - older_x) + 1; /* +1: to avoid a division by zero below. */
   2 dy = abs(new_y - older_y) + 1;
   3 
   4 /* "len" is really the length squared. */
   5 len = (dx * dx) + (dy * dy);
   6 
   7 /* "sysctl_weight_len_squared" is the length squared at which the
   8  * "weight_previous" will start to decrease. */
   9 weight_previous = sysctl_weight_len_squared * weight_previous / len;
  10 weight_previous = imin(weight_previous, sysctl_weight_previous);

The driver will do almost the same with the divisor to calculate the acceleration. The rest of the division is also kept between each packet; otherwise, with slow movements, the pointer doesn't reproduce well what the finger is doing.

SynapticsTouchpad (last edited 2009-07-30 08:55:04 by JeanSébastienPédron)