|
@@ -268,19 +268,49 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int synaptics_set_absolute_mode(struct psmouse *psmouse)
|
|
|
+static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
|
|
|
+{
|
|
|
+ static unsigned char param = 0xc8;
|
|
|
+ struct synaptics_data *priv = psmouse->private;
|
|
|
+
|
|
|
+ if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ /* Advanced gesture mode also sends multi finger data */
|
|
|
+ priv->capabilities |= BIT(1);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int synaptics_set_mode(struct psmouse *psmouse)
|
|
|
{
|
|
|
struct synaptics_data *priv = psmouse->private;
|
|
|
|
|
|
- priv->mode = SYN_BIT_ABSOLUTE_MODE;
|
|
|
- if (SYN_ID_MAJOR(priv->identity) >= 4)
|
|
|
+ priv->mode = 0;
|
|
|
+ if (priv->absolute_mode)
|
|
|
+ priv->mode |= SYN_BIT_ABSOLUTE_MODE;
|
|
|
+ if (priv->disable_gesture)
|
|
|
priv->mode |= SYN_BIT_DISABLE_GESTURE;
|
|
|
+ if (psmouse->rate >= 80)
|
|
|
+ priv->mode |= SYN_BIT_HIGH_RATE;
|
|
|
if (SYN_CAP_EXTENDED(priv->capabilities))
|
|
|
priv->mode |= SYN_BIT_W_MODE;
|
|
|
|
|
|
if (synaptics_mode_cmd(psmouse, priv->mode))
|
|
|
return -1;
|
|
|
|
|
|
+ if (priv->absolute_mode &&
|
|
|
+ synaptics_set_advanced_gesture_mode(psmouse)) {
|
|
|
+ psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -299,26 +329,6 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
|
|
|
synaptics_mode_cmd(psmouse, priv->mode);
|
|
|
}
|
|
|
|
|
|
-static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
|
|
|
-{
|
|
|
- static unsigned char param = 0xc8;
|
|
|
- struct synaptics_data *priv = psmouse->private;
|
|
|
-
|
|
|
- if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
|
|
|
- SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
|
|
|
- return -1;
|
|
|
- if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE))
|
|
|
- return -1;
|
|
|
-
|
|
|
- /* Advanced gesture mode also sends multi finger data */
|
|
|
- priv->capabilities |= BIT(1);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
/*****************************************************************************
|
|
|
* Synaptics pass-through PS/2 port support
|
|
|
****************************************************************************/
|
|
@@ -1142,8 +1152,24 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
+ /* Things that apply to both modes */
|
|
|
__set_bit(INPUT_PROP_POINTER, dev->propbit);
|
|
|
+ __set_bit(EV_KEY, dev->evbit);
|
|
|
+ __set_bit(BTN_LEFT, dev->keybit);
|
|
|
+ __set_bit(BTN_RIGHT, dev->keybit);
|
|
|
|
|
|
+ if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
|
|
+ __set_bit(BTN_MIDDLE, dev->keybit);
|
|
|
+
|
|
|
+ if (!priv->absolute_mode) {
|
|
|
+ /* Relative mode */
|
|
|
+ __set_bit(EV_REL, dev->evbit);
|
|
|
+ __set_bit(REL_X, dev->relbit);
|
|
|
+ __set_bit(REL_Y, dev->relbit);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Absolute mode */
|
|
|
__set_bit(EV_ABS, dev->evbit);
|
|
|
set_abs_position_params(dev, priv, ABS_X, ABS_Y);
|
|
|
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
|
@@ -1169,20 +1195,14 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
|
|
if (SYN_CAP_PALMDETECT(priv->capabilities))
|
|
|
input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
|
|
|
|
|
|
- __set_bit(EV_KEY, dev->evbit);
|
|
|
__set_bit(BTN_TOUCH, dev->keybit);
|
|
|
__set_bit(BTN_TOOL_FINGER, dev->keybit);
|
|
|
- __set_bit(BTN_LEFT, dev->keybit);
|
|
|
- __set_bit(BTN_RIGHT, dev->keybit);
|
|
|
|
|
|
if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
|
|
|
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
|
|
|
__set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
|
|
|
}
|
|
|
|
|
|
- if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
|
|
- __set_bit(BTN_MIDDLE, dev->keybit);
|
|
|
-
|
|
|
if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
|
|
|
SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
|
|
|
__set_bit(BTN_FORWARD, dev->keybit);
|
|
@@ -1204,10 +1224,58 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
|
|
|
+ void *data, char *buf)
|
|
|
+{
|
|
|
+ struct synaptics_data *priv = psmouse->private;
|
|
|
+
|
|
|
+ return sprintf(buf, "%c\n", priv->disable_gesture ? '1' : '0');
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t synaptics_set_disable_gesture(struct psmouse *psmouse,
|
|
|
+ void *data, const char *buf,
|
|
|
+ size_t len)
|
|
|
+{
|
|
|
+ struct synaptics_data *priv = psmouse->private;
|
|
|
+ unsigned int value;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = kstrtouint(buf, 10, &value);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (value > 1)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (value == priv->disable_gesture)
|
|
|
+ return len;
|
|
|
+
|
|
|
+ priv->disable_gesture = value;
|
|
|
+ if (value)
|
|
|
+ priv->mode |= SYN_BIT_DISABLE_GESTURE;
|
|
|
+ else
|
|
|
+ priv->mode &= ~SYN_BIT_DISABLE_GESTURE;
|
|
|
+
|
|
|
+ if (synaptics_mode_cmd(psmouse, priv->mode))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL,
|
|
|
+ synaptics_show_disable_gesture,
|
|
|
+ synaptics_set_disable_gesture);
|
|
|
+
|
|
|
static void synaptics_disconnect(struct psmouse *psmouse)
|
|
|
{
|
|
|
+ struct synaptics_data *priv = psmouse->private;
|
|
|
+
|
|
|
+ if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity))
|
|
|
+ device_remove_file(&psmouse->ps2dev.serio->dev,
|
|
|
+ &psmouse_attr_disable_gesture.dattr);
|
|
|
+
|
|
|
synaptics_reset(psmouse);
|
|
|
- kfree(psmouse->private);
|
|
|
+ kfree(priv);
|
|
|
psmouse->private = NULL;
|
|
|
}
|
|
|
|
|
@@ -1234,17 +1302,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- if (synaptics_set_absolute_mode(psmouse)) {
|
|
|
+ if (synaptics_set_mode(psmouse)) {
|
|
|
psmouse_err(psmouse, "Unable to initialize device.\n");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- if (synaptics_set_advanced_gesture_mode(psmouse)) {
|
|
|
- psmouse_err(psmouse,
|
|
|
- "Advanced gesture mode reconnect failed.\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
if (old_priv.identity != priv->identity ||
|
|
|
old_priv.model_id != priv->model_id ||
|
|
|
old_priv.capabilities != priv->capabilities ||
|
|
@@ -1321,9 +1383,10 @@ void __init synaptics_module_init(void)
|
|
|
broken_olpc_ec = dmi_check_system(olpc_dmi_table);
|
|
|
}
|
|
|
|
|
|
-int synaptics_init(struct psmouse *psmouse)
|
|
|
+static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
|
|
|
{
|
|
|
struct synaptics_data *priv;
|
|
|
+ int err = -1;
|
|
|
|
|
|
/*
|
|
|
* The OLPC XO has issues with Synaptics' absolute mode; similarly to
|
|
@@ -1351,13 +1414,12 @@ int synaptics_init(struct psmouse *psmouse)
|
|
|
goto init_fail;
|
|
|
}
|
|
|
|
|
|
- if (synaptics_set_absolute_mode(psmouse)) {
|
|
|
- psmouse_err(psmouse, "Unable to initialize device.\n");
|
|
|
- goto init_fail;
|
|
|
- }
|
|
|
+ priv->absolute_mode = absolute_mode;
|
|
|
+ if (SYN_ID_DISGEST_SUPPORTED(priv->identity))
|
|
|
+ priv->disable_gesture = true;
|
|
|
|
|
|
- if (synaptics_set_advanced_gesture_mode(psmouse)) {
|
|
|
- psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
|
|
|
+ if (synaptics_set_mode(psmouse)) {
|
|
|
+ psmouse_err(psmouse, "Unable to initialize device.\n");
|
|
|
goto init_fail;
|
|
|
}
|
|
|
|
|
@@ -1382,12 +1444,19 @@ int synaptics_init(struct psmouse *psmouse)
|
|
|
psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
|
|
|
(priv->model_id & 0x000000ff);
|
|
|
|
|
|
- psmouse->protocol_handler = synaptics_process_byte;
|
|
|
+ if (absolute_mode) {
|
|
|
+ psmouse->protocol_handler = synaptics_process_byte;
|
|
|
+ psmouse->pktsize = 6;
|
|
|
+ } else {
|
|
|
+ /* Relative mode follows standard PS/2 mouse protocol */
|
|
|
+ psmouse->protocol_handler = psmouse_process_byte;
|
|
|
+ psmouse->pktsize = 3;
|
|
|
+ }
|
|
|
+
|
|
|
psmouse->set_rate = synaptics_set_rate;
|
|
|
psmouse->disconnect = synaptics_disconnect;
|
|
|
psmouse->reconnect = synaptics_reconnect;
|
|
|
psmouse->cleanup = synaptics_reset;
|
|
|
- psmouse->pktsize = 6;
|
|
|
/* Synaptics can usually stay in sync without extra help */
|
|
|
psmouse->resync_time = 0;
|
|
|
|
|
@@ -1406,11 +1475,32 @@ int synaptics_init(struct psmouse *psmouse)
|
|
|
psmouse->rate = 40;
|
|
|
}
|
|
|
|
|
|
+ if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) {
|
|
|
+ err = device_create_file(&psmouse->ps2dev.serio->dev,
|
|
|
+ &psmouse_attr_disable_gesture.dattr);
|
|
|
+ if (err) {
|
|
|
+ psmouse_err(psmouse,
|
|
|
+ "Failed to create disable_gesture attribute (%d)",
|
|
|
+ err);
|
|
|
+ goto init_fail;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
init_fail:
|
|
|
kfree(priv);
|
|
|
- return -1;
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+int synaptics_init(struct psmouse *psmouse)
|
|
|
+{
|
|
|
+ return __synaptics_init(psmouse, true);
|
|
|
+}
|
|
|
+
|
|
|
+int synaptics_init_relative(struct psmouse *psmouse)
|
|
|
+{
|
|
|
+ return __synaptics_init(psmouse, false);
|
|
|
}
|
|
|
|
|
|
bool synaptics_supported(void)
|