Message ID | 1270749698-20872-2-git-send-email-chase.douglas@canonical.com |
---|---|
State | Accepted |
Delegated to: | Andy Whitcroft |
Headers | show |
On Thu, Apr 08, 2010 at 02:01:38PM -0400, Chase Douglas wrote: > From: Takashi Iwai <tiwai@xxxxxxx> > > Add the experimental support of new Synatpics "Clickpad" devices. > > This device reports the click as the middle-button, but it doesn't set > proper capability bits. Thus the driver needs to check the product-id > and forces to enable the button detection. > > In this patch, the device behaves as "ClickZone" mode, and gives > compatible events as other normal synaptics devices so that user-space > app works as is. In the ClickZone mode, the buttons are emulated as > clicks in the bottom button zone. Left and right clicks are judged by > the touch position. Clicking the narrow middle point in the button > zone gives a middle click. > > Dragging can be done by keeping the button down and touching the normal > area again. Strangely, the sequence to click after touching the area > doesn't work with this device by unknown reason... > > Signed-off-by: Takashi Iwai <tiwai@xxxxxxx> > > BugLink: http://bugs.launchpad.net/bugs/516329 > > Signed-off-by: Chase Douglas <chase.douglas@canonical.com> > --- > > This is the second version, simply merged previous patches into one, > per request of Dmitry. > > drivers/input/mouse/synaptics.c | 48 +++++++++++++++++++++++++++++++++++++++ > drivers/input/mouse/synaptics.h | 3 ++ > 2 files changed, 51 insertions(+), 0 deletions(-) > > diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c > index 05689e7..b2db417 100644 > --- a/drivers/input/mouse/synaptics.c > +++ b/drivers/input/mouse/synaptics.c > @@ -327,6 +327,45 @@ static void synaptics_pt_create(struct psmouse *psmouse) > * Functions to interpret the absolute mode packets > ****************************************************************************/ > > +/* left and right clickpad button ranges; > + * the gap between them is interpreted as a middle-button click > + */ > +#define CLICKPAD_LEFT_BTN_X \ > + ((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL) > +#define CLICKPAD_RIGHT_BTN_X \ > + ((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL) > + > +/* handle clickpad events */ > +static void clickpad_process_packet(struct synaptics_data *priv, > + struct synaptics_hw_state *hw) > +{ > + /* clickpad mode reports Y range from 0 to YMAX_NOMINAL, > + * where the area Y < YMIN_NOMINAL is used as click buttons > + */ > + if (hw->y < YMIN_NOMINAL) { > + /* button area */ > + hw->z = 0; /* don't move pointer */ > + /* clickpad reports only the middle button, and we need > + * to fake left/right buttons depending on the touch position > + */ > + if (hw->middle) { /* clicked? */ > + hw->middle = 0; > + if (hw->x < CLICKPAD_LEFT_BTN_X) > + hw->left = 1; > + else if (hw->x > CLICKPAD_RIGHT_BTN_X) > + hw->right = 1; > + else > + hw->middle = 1; > + } > + } else if (hw->middle) { > + /* dragging */ > + hw->left = priv->prev_hw.left; > + hw->right = priv->prev_hw.right; > + hw->middle = priv->prev_hw.middle; > + } > + priv->prev_hw = *hw; > +} > + > static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) > { > memset(hw, 0, sizeof(struct synaptics_hw_state)); > @@ -407,6 +446,9 @@ static void synaptics_process_packet(struct psmouse *psmouse) > > synaptics_parse_hw_state(psmouse->packet, priv, &hw); > > + if (SYN_CAP_CLICKPAD(priv->ext_cap)) > + clickpad_process_packet(priv, &hw); > + > if (hw.scroll) { > priv->scroll += hw.scroll; > > @@ -701,6 +743,12 @@ int synaptics_init(struct psmouse *psmouse) > SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), > priv->model_id, priv->capabilities, priv->ext_cap); > > + if (SYN_CAP_CLICKPAD(priv->ext_cap)) { > + printk(KERN_INFO "Synaptics: Clickpad mode enabled\n"); > + /* force to enable the middle button */ > + priv->capabilities |= (1 << 18); > + } > + > set_input_params(psmouse->dev, priv); > > /* > diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h > index 838e7f2..76df393 100644 > --- a/drivers/input/mouse/synaptics.h > +++ b/drivers/input/mouse/synaptics.h > @@ -48,6 +48,8 @@ > #define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) > #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) > #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) > +#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) > +#define SYN_CAP_CLICKPAD(ec) (SYN_CAP_PRODUCT_ID(ec) == 0xe4) > > /* synaptics modes query bits */ > #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) > @@ -103,6 +105,7 @@ struct synaptics_data { > unsigned char pkt_type; /* packet type - old, new, etc */ > unsigned char mode; /* current mode byte */ > int scroll; > + struct synaptics_hw_state prev_hw; > }; Seems to only enable the functionality for devices with the capability and to be nicely out of line otherwise. Acked-by: Andy Whitcroft <apw@canonical.com> -apw
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 05689e7..b2db417 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -327,6 +327,45 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ +/* left and right clickpad button ranges; + * the gap between them is interpreted as a middle-button click + */ +#define CLICKPAD_LEFT_BTN_X \ + ((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL) +#define CLICKPAD_RIGHT_BTN_X \ + ((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL) + +/* handle clickpad events */ +static void clickpad_process_packet(struct synaptics_data *priv, + struct synaptics_hw_state *hw) +{ + /* clickpad mode reports Y range from 0 to YMAX_NOMINAL, + * where the area Y < YMIN_NOMINAL is used as click buttons + */ + if (hw->y < YMIN_NOMINAL) { + /* button area */ + hw->z = 0; /* don't move pointer */ + /* clickpad reports only the middle button, and we need + * to fake left/right buttons depending on the touch position + */ + if (hw->middle) { /* clicked? */ + hw->middle = 0; + if (hw->x < CLICKPAD_LEFT_BTN_X) + hw->left = 1; + else if (hw->x > CLICKPAD_RIGHT_BTN_X) + hw->right = 1; + else + hw->middle = 1; + } + } else if (hw->middle) { + /* dragging */ + hw->left = priv->prev_hw.left; + hw->right = priv->prev_hw.right; + hw->middle = priv->prev_hw.middle; + } + priv->prev_hw = *hw; +} + static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { memset(hw, 0, sizeof(struct synaptics_hw_state)); @@ -407,6 +446,9 @@ static void synaptics_process_packet(struct psmouse *psmouse) synaptics_parse_hw_state(psmouse->packet, priv, &hw); + if (SYN_CAP_CLICKPAD(priv->ext_cap)) + clickpad_process_packet(priv, &hw); + if (hw.scroll) { priv->scroll += hw.scroll; @@ -701,6 +743,12 @@ int synaptics_init(struct psmouse *psmouse) SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), priv->model_id, priv->capabilities, priv->ext_cap); + if (SYN_CAP_CLICKPAD(priv->ext_cap)) { + printk(KERN_INFO "Synaptics: Clickpad mode enabled\n"); + /* force to enable the middle button */ + priv->capabilities |= (1 << 18); + } + set_input_params(psmouse->dev, priv); /* diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 838e7f2..76df393 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -48,6 +48,8 @@ #define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) +#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) +#define SYN_CAP_CLICKPAD(ec) (SYN_CAP_PRODUCT_ID(ec) == 0xe4) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) @@ -103,6 +105,7 @@ struct synaptics_data { unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ int scroll; + struct synaptics_hw_state prev_hw; }; void synaptics_module_init(void);