At Fri, 08 Oct 2010 18:38:38 +0200, Takashi Iwai wrote: > > At Fri, 08 Oct 2010 18:37:22 +0200, > Takashi Iwai wrote: > > > > At Fri, 8 Oct 2010 10:57:57 -0400, > > Chase Douglas wrote: > > > > > > Tobyn Bertram reverse engineered the multitouch protocol for Synaptics devices. > > > I've been able to take his work and produce a series of commits to enable MT > > > and multifinger (MF) support. > > > > > > Unfortunately, there's a tricky issue with some Synaptics touchpads that have > > > integrated buttons. For example, the left and right buttons on the touchpad of > > > my Dell Mini 1012 consist of the lower ~20% of the touchpad surface. The > > > touchpad physically clicks under these areas. > > > > > > The X synaptics input module now has a parameter to disable touches occuring > > > over the button area, but this solution still doesn't work perfectly. If you > > > click a button and drag with another finger near the clicking finger, the > > > touchpad gets confused. > > > > > > Now that we have full MT support, we can try to handle this scenario better. > > > What I've found to work best is to make touches vanish if they occur over the > > > button area of the trackpad while any button is held. This works in conjunction > > > with the X synaptics driver to disable single touch control over the button > > > area. With full MT support, the touchpad doesn't seem to get confused when a > > > click and drag occurs with two fingers close to each other, and it enables MT > > > gestures and MF support across the entire trackpad when no buttons are held. > > > > > > The first question is whether this seems appropriate to others, or if some > > > other method would work better. Secondarily, should the solution occur in the > > > kernel, like I have in the third patch of this series, or should it occur in > > > the X input module? Although we don't have this information today, we may be > > > able to query the touchpad in the future to know the area of the integrated > > > buttons. If that were possible, would the recommended location for the hack > > > change? > > > > Great! Finally someone found it out! > > I found this and made a series of patches in 4 months ago. Since > > then, Novell legal prohibited me to send the patches to the upstream > > due to "possible patent infringing". Now you cracked out. Yay. > > > > FWIW, my corresponding patch is below. It really looks similar in the > > end ;) I added a kconfig just to be safer. > > > > Regarding the "clickpad" support: in my case, I implemented almost > > everything about it in xorg driver. I'm going to submit xorg > > patches. > > BTW, yet another kernel patch is missing; the support of embedded LED. > I've posted this once, but it seems forgotten since then. Reposted > below. Oh, any yet another patch, which enables multi-touch mode forcibly. I see a similar option in your patch, so this might be useless. But, I found that some old laptops have a little MT-support although they have no such capability bit. They can detect multi-fingers but can't track the positions, it seems. We'd need to add some whitelist for such devices. Takashi --- From: Takashi Iwai <tiwai@xxxxxxx> Subject: Add multi_touch parameter to psmouse driver The multi-touch feature of Synaptics device is disabled unless this option is set. Setting to 2 forces the multi-touch mode no matter whether the feature is detected or not. Signed-off-by: Takashi Iwai <tiwai@xxxxxxx> --- drivers/input/mouse/synaptics.c | 106 +++++++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 23 deletions(-) --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -482,10 +482,88 @@ } #ifdef CONFIG_MOUSE_PS2_SYNAPTICS_MULTI_TOUCH -#define is_multi_touch(priv) (priv)->can_multi_touch +static int multi_touch_flag; + +static void setup_multi_touch(struct psmouse *psmouse, int verbose); + +static struct psmouse *_psmouse; + +static int param_set_multi_touch(const char *val, const struct kernel_param *kp) +{ + int mode, mode_changed; + + if (!val) + return -EINVAL; + mode = simple_strtol(val, NULL, 0); + if (mode < 0 || mode > 2) + return -EINVAL; + mode_changed = mode != multi_touch_flag; + multi_touch_flag = mode; + if (mode_changed) + setup_multi_touch(_psmouse, 1); + return 0; +} + +#define param_check_multi_touch(name, p) __param_check(name, p, int) + +static struct kernel_param_ops param_ops_multi_touch = { + .set = param_set_multi_touch, + .get = param_get_int, +}; + +module_param_named(multi_touch, multi_touch_flag, multi_touch, 0644); + +static inline int is_multi_touch(struct synaptics_data *priv) +{ + return (multi_touch_flag == 2 || + (priv->can_multi_touch && multi_touch_flag)); +} + +static void setup_multi_touch(struct psmouse *psmouse, int verbose) +{ + struct input_dev *dev; + struct synaptics_data *priv; + + _psmouse = psmouse; + if (!psmouse) + return; + dev = psmouse->dev; + priv = psmouse->private; + if (!dev || !priv) + return; + if (is_multi_touch(priv) && + !synaptics_init_multi_touch(psmouse)) { + if (verbose) + printk(KERN_INFO "Synaptics: enabling multi-touch\n"); + if (!SYN_CAP_MULTIFINGER(priv->capabilities)) { + __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); + __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); + } + input_set_abs_params(dev, ABS_MT_POSITION_X, + XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, + YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res); + input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res); + } else { + if (verbose) + printk(KERN_INFO "Synaptics: disabling multi-touch\n"); + if (!SYN_CAP_MULTIFINGER(priv->capabilities)) { + __clear_bit(BTN_TOOL_DOUBLETAP, dev->keybit); + __clear_bit(BTN_TOOL_TRIPLETAP, dev->keybit); + } + __clear_bit(ABS_MT_POSITION_X, dev->absbit); + __clear_bit(ABS_MT_POSITION_Y, dev->absbit); + __clear_bit(ABS_MT_PRESSURE, dev->absbit); + } +} + #else #define is_multi_touch(priv) 0 +#define setup_multi_touch(ps, v) do { } while (0) #endif + /* the multi-touch packet contains w=2 (like pen) */ #define is_multi_touch_packet(priv, hw) \ (is_multi_touch(priv) && (hw)->w == 2) @@ -781,7 +859,7 @@ __set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); - if (SYN_CAP_MULTIFINGER(priv->capabilities) || is_multi_touch(priv)) { + if (SYN_CAP_MULTIFINGER(priv->capabilities)) { __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); } @@ -810,20 +888,11 @@ __clear_bit(BTN_RIGHT, dev->keybit); __clear_bit(BTN_MIDDLE, dev->keybit); } - - if (is_multi_touch(priv)) { - input_set_abs_params(dev, ABS_MT_POSITION_X, - XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, - YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); - input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res); - input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res); - } } static void synaptics_disconnect(struct psmouse *psmouse) { + setup_multi_touch(NULL, 0); synaptics_free_led(psmouse); synaptics_reset(psmouse); kfree(psmouse->private); @@ -857,8 +926,7 @@ } synaptics_sync_led(psmouse); - if (is_multi_touch(priv)) - synaptics_init_multi_touch(psmouse); + setup_multi_touch(psmouse, 0); return 0; } @@ -937,16 +1005,8 @@ if (synaptics_init_led(psmouse) < 0) goto init_fail; - if (priv->can_multi_touch) { - if (synaptics_init_multi_touch(psmouse)) { - printk(KERN_WARNING "Synaptics: " - "unable to initialize multi-touch\n"); - priv->can_multi_touch = 0; - } else - printk(KERN_INFO "Synaptics: multi-touch enabled\n"); - } - set_input_params(psmouse->dev, priv); + setup_multi_touch(psmouse, 0); /* * Encode touchpad model so that it can be used to set -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html