aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2011-11-08 03:00:35 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-11-10 00:23:31 -0500
commit7968a5dd492ccc38345013e534ad4c8d6eb60ed1 (patch)
treeb7ba40bb0dc4c92471a40e5879e95abdc9b5036f /drivers
parent76496e7a02e99d42844f4fffa145b81e513e7acd (diff)
Input: synaptics - add support for Relative mode
Currently, the synaptics driver puts the device into Absolute mode. As explained in the synaptics documentation section 3.2, in this mode, the device sends a continuous stream of packets at the maximum rate to the host when the user's fingers are near or on the pad or pressing buttons, and continues streaming for 1 second afterwards. These packets are even sent when there is no new information to report, even when they are duplicates of the previous packet. For embedded systems this is a bit much - it results in a huge and uninterrupted stream of interrupts at high rate. This patch adds support for Relative mode, which can be selected as a new psmouse protocol. In this mode, the device does not send duplicate packets and acts like a standard PS/2 mouse. However, synaptics-specific functionality is still available, such as the ability to set the packet rate, and rather than disabling gestures and taps at the hardware level unconditionally, a 'synaptics_disable_gesture' sysfs attribute has been added to allow control of this functionality. This solves a long standing OLPC issue: synaptics hardware enables tap to click by default (even in the default relative mode), but we have found this to be inappropriate for young children and first time computer users. Enabling the synaptics driver disables tap-to-click, but we have previously been unable to use this because it also enables Absolute mode, which is too "spammy" for our desires and actually overloads our EC with its continuous stream of packets. Now we can enable the synaptics driver, disabling tap to click while retaining the less noisy Relative mode. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/mouse/psmouse-base.c9
-rw-r--r--drivers/input/mouse/psmouse.h2
-rw-r--r--drivers/input/mouse/synaptics.c184
-rw-r--r--drivers/input/mouse/synaptics.h5
4 files changed, 152 insertions, 48 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index a6973e575aa9..200be9c9dbc7 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -127,7 +127,7 @@ struct psmouse_protocol {
127 * relevant events to the input module once full packet has arrived. 127 * relevant events to the input module once full packet has arrived.
128 */ 128 */
129 129
130static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) 130psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
131{ 131{
132 struct input_dev *dev = psmouse->dev; 132 struct input_dev *dev = psmouse->dev;
133 unsigned char *packet = psmouse->packet; 133 unsigned char *packet = psmouse->packet;
@@ -819,6 +819,13 @@ static const struct psmouse_protocol psmouse_protocols[] = {
819 .detect = synaptics_detect, 819 .detect = synaptics_detect,
820 .init = synaptics_init, 820 .init = synaptics_init,
821 }, 821 },
822 {
823 .type = PSMOUSE_SYNAPTICS_RELATIVE,
824 .name = "SynRelPS/2",
825 .alias = "synaptics-relative",
826 .detect = synaptics_detect,
827 .init = synaptics_init_relative,
828 },
822#endif 829#endif
823#ifdef CONFIG_MOUSE_PS2_ALPS 830#ifdef CONFIG_MOUSE_PS2_ALPS
824 { 831 {
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 11a9c6c8bca4..6a417092d010 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -94,6 +94,7 @@ enum psmouse_type {
94 PSMOUSE_HGPK, 94 PSMOUSE_HGPK,
95 PSMOUSE_ELANTECH, 95 PSMOUSE_ELANTECH,
96 PSMOUSE_FSP, 96 PSMOUSE_FSP,
97 PSMOUSE_SYNAPTICS_RELATIVE,
97 PSMOUSE_AUTO /* This one should always be last */ 98 PSMOUSE_AUTO /* This one should always be last */
98}; 99};
99 100
@@ -103,6 +104,7 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
103int psmouse_reset(struct psmouse *psmouse); 104int psmouse_reset(struct psmouse *psmouse);
104void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); 105void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
105void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); 106void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
107psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse);
106 108
107struct psmouse_attribute { 109struct psmouse_attribute {
108 struct device_attribute dattr; 110 struct device_attribute dattr;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index c080b828e5dc..a3bb49cb691c 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -268,19 +268,49 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
268 return 0; 268 return 0;
269} 269}
270 270
271static int synaptics_set_absolute_mode(struct psmouse *psmouse) 271static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
272{
273 static unsigned char param = 0xc8;
274 struct synaptics_data *priv = psmouse->private;
275
276 if (!SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
277 return 0;
278
279 if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
280 return -1;
281
282 if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
283 return -1;
284
285 /* Advanced gesture mode also sends multi finger data */
286 priv->capabilities |= BIT(1);
287
288 return 0;
289}
290
291static int synaptics_set_mode(struct psmouse *psmouse)
272{ 292{
273 struct synaptics_data *priv = psmouse->private; 293 struct synaptics_data *priv = psmouse->private;
274 294
275 priv->mode = SYN_BIT_ABSOLUTE_MODE; 295 priv->mode = 0;
276 if (SYN_ID_MAJOR(priv->identity) >= 4) 296 if (priv->absolute_mode)
297 priv->mode |= SYN_BIT_ABSOLUTE_MODE;
298 if (priv->disable_gesture)
277 priv->mode |= SYN_BIT_DISABLE_GESTURE; 299 priv->mode |= SYN_BIT_DISABLE_GESTURE;
300 if (psmouse->rate >= 80)
301 priv->mode |= SYN_BIT_HIGH_RATE;
278 if (SYN_CAP_EXTENDED(priv->capabilities)) 302 if (SYN_CAP_EXTENDED(priv->capabilities))
279 priv->mode |= SYN_BIT_W_MODE; 303 priv->mode |= SYN_BIT_W_MODE;
280 304
281 if (synaptics_mode_cmd(psmouse, priv->mode)) 305 if (synaptics_mode_cmd(psmouse, priv->mode))
282 return -1; 306 return -1;
283 307
308 if (priv->absolute_mode &&
309 synaptics_set_advanced_gesture_mode(psmouse)) {
310 psmouse_err(psmouse, "Advanced gesture mode init failed.\n");
311 return -1;
312 }
313
284 return 0; 314 return 0;
285} 315}
286 316
@@ -299,26 +329,6 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate)
299 synaptics_mode_cmd(psmouse, priv->mode); 329 synaptics_mode_cmd(psmouse, priv->mode);
300} 330}
301 331
302static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse)
303{
304 static unsigned char param = 0xc8;
305 struct synaptics_data *priv = psmouse->private;
306
307 if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
308 SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)))
309 return 0;
310
311 if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL))
312 return -1;
313 if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE))
314 return -1;
315
316 /* Advanced gesture mode also sends multi finger data */
317 priv->capabilities |= BIT(1);
318
319 return 0;
320}
321
322/***************************************************************************** 332/*****************************************************************************
323 * Synaptics pass-through PS/2 port support 333 * Synaptics pass-through PS/2 port support
324 ****************************************************************************/ 334 ****************************************************************************/
@@ -1142,8 +1152,24 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
1142{ 1152{
1143 int i; 1153 int i;
1144 1154
1155 /* Things that apply to both modes */
1145 __set_bit(INPUT_PROP_POINTER, dev->propbit); 1156 __set_bit(INPUT_PROP_POINTER, dev->propbit);
1157 __set_bit(EV_KEY, dev->evbit);
1158 __set_bit(BTN_LEFT, dev->keybit);
1159 __set_bit(BTN_RIGHT, dev->keybit);
1146 1160
1161 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
1162 __set_bit(BTN_MIDDLE, dev->keybit);
1163
1164 if (!priv->absolute_mode) {
1165 /* Relative mode */
1166 __set_bit(EV_REL, dev->evbit);
1167 __set_bit(REL_X, dev->relbit);
1168 __set_bit(REL_Y, dev->relbit);
1169 return;
1170 }
1171
1172 /* Absolute mode */
1147 __set_bit(EV_ABS, dev->evbit); 1173 __set_bit(EV_ABS, dev->evbit);
1148 set_abs_position_params(dev, priv, ABS_X, ABS_Y); 1174 set_abs_position_params(dev, priv, ABS_X, ABS_Y);
1149 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); 1175 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)
1169 if (SYN_CAP_PALMDETECT(priv->capabilities)) 1195 if (SYN_CAP_PALMDETECT(priv->capabilities))
1170 input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); 1196 input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
1171 1197
1172 __set_bit(EV_KEY, dev->evbit);
1173 __set_bit(BTN_TOUCH, dev->keybit); 1198 __set_bit(BTN_TOUCH, dev->keybit);
1174 __set_bit(BTN_TOOL_FINGER, dev->keybit); 1199 __set_bit(BTN_TOOL_FINGER, dev->keybit);
1175 __set_bit(BTN_LEFT, dev->keybit);
1176 __set_bit(BTN_RIGHT, dev->keybit);
1177 1200
1178 if (SYN_CAP_MULTIFINGER(priv->capabilities)) { 1201 if (SYN_CAP_MULTIFINGER(priv->capabilities)) {
1179 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); 1202 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
1180 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); 1203 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
1181 } 1204 }
1182 1205
1183 if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
1184 __set_bit(BTN_MIDDLE, dev->keybit);
1185
1186 if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || 1206 if (SYN_CAP_FOUR_BUTTON(priv->capabilities) ||
1187 SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { 1207 SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
1188 __set_bit(BTN_FORWARD, dev->keybit); 1208 __set_bit(BTN_FORWARD, dev->keybit);
@@ -1204,10 +1224,58 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
1204 } 1224 }
1205} 1225}
1206 1226
1227static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse,
1228 void *data, char *buf)
1229{
1230 struct synaptics_data *priv = psmouse->private;
1231
1232 return sprintf(buf, "%c\n", priv->disable_gesture ? '1' : '0');
1233}
1234
1235static ssize_t synaptics_set_disable_gesture(struct psmouse *psmouse,
1236 void *data, const char *buf,
1237 size_t len)
1238{
1239 struct synaptics_data *priv = psmouse->private;
1240 unsigned int value;
1241 int err;
1242
1243 err = kstrtouint(buf, 10, &value);
1244 if (err)
1245 return err;
1246
1247 if (value > 1)
1248 return -EINVAL;
1249
1250 if (value == priv->disable_gesture)
1251 return len;
1252
1253 priv->disable_gesture = value;
1254 if (value)
1255 priv->mode |= SYN_BIT_DISABLE_GESTURE;
1256 else
1257 priv->mode &= ~SYN_BIT_DISABLE_GESTURE;
1258
1259 if (synaptics_mode_cmd(psmouse, priv->mode))
1260 return -EIO;
1261
1262 return len;
1263}
1264
1265PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL,
1266 synaptics_show_disable_gesture,
1267 synaptics_set_disable_gesture);
1268
1207static void synaptics_disconnect(struct psmouse *psmouse) 1269static void synaptics_disconnect(struct psmouse *psmouse)
1208{ 1270{
1271 struct synaptics_data *priv = psmouse->private;
1272
1273 if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity))
1274 device_remove_file(&psmouse->ps2dev.serio->dev,
1275 &psmouse_attr_disable_gesture.dattr);
1276
1209 synaptics_reset(psmouse); 1277 synaptics_reset(psmouse);
1210 kfree(psmouse->private); 1278 kfree(priv);
1211 psmouse->private = NULL; 1279 psmouse->private = NULL;
1212} 1280}
1213 1281
@@ -1234,17 +1302,11 @@ static int synaptics_reconnect(struct psmouse *psmouse)
1234 return -1; 1302 return -1;
1235 } 1303 }
1236 1304
1237 if (synaptics_set_absolute_mode(psmouse)) { 1305 if (synaptics_set_mode(psmouse)) {
1238 psmouse_err(psmouse, "Unable to initialize device.\n"); 1306 psmouse_err(psmouse, "Unable to initialize device.\n");
1239 return -1; 1307 return -1;
1240 } 1308 }
1241 1309
1242 if (synaptics_set_advanced_gesture_mode(psmouse)) {
1243 psmouse_err(psmouse,
1244 "Advanced gesture mode reconnect failed.\n");
1245 return -1;
1246 }
1247
1248 if (old_priv.identity != priv->identity || 1310 if (old_priv.identity != priv->identity ||
1249 old_priv.model_id != priv->model_id || 1311 old_priv.model_id != priv->model_id ||
1250 old_priv.capabilities != priv->capabilities || 1312 old_priv.capabilities != priv->capabilities ||
@@ -1321,9 +1383,10 @@ void __init synaptics_module_init(void)
1321 broken_olpc_ec = dmi_check_system(olpc_dmi_table); 1383 broken_olpc_ec = dmi_check_system(olpc_dmi_table);
1322} 1384}
1323 1385
1324int synaptics_init(struct psmouse *psmouse) 1386static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
1325{ 1387{
1326 struct synaptics_data *priv; 1388 struct synaptics_data *priv;
1389 int err = -1;
1327 1390
1328 /* 1391 /*
1329 * The OLPC XO has issues with Synaptics' absolute mode; similarly to 1392 * The OLPC XO has issues with Synaptics' absolute mode; similarly to
@@ -1351,13 +1414,12 @@ int synaptics_init(struct psmouse *psmouse)
1351 goto init_fail; 1414 goto init_fail;
1352 } 1415 }
1353 1416
1354 if (synaptics_set_absolute_mode(psmouse)) { 1417 priv->absolute_mode = absolute_mode;
1355 psmouse_err(psmouse, "Unable to initialize device.\n"); 1418 if (SYN_ID_DISGEST_SUPPORTED(priv->identity))
1356 goto init_fail; 1419 priv->disable_gesture = true;
1357 }
1358 1420
1359 if (synaptics_set_advanced_gesture_mode(psmouse)) { 1421 if (synaptics_set_mode(psmouse)) {
1360 psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); 1422 psmouse_err(psmouse, "Unable to initialize device.\n");
1361 goto init_fail; 1423 goto init_fail;
1362 } 1424 }
1363 1425
@@ -1382,12 +1444,19 @@ int synaptics_init(struct psmouse *psmouse)
1382 psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) | 1444 psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
1383 (priv->model_id & 0x000000ff); 1445 (priv->model_id & 0x000000ff);
1384 1446
1385 psmouse->protocol_handler = synaptics_process_byte; 1447 if (absolute_mode) {
1448 psmouse->protocol_handler = synaptics_process_byte;
1449 psmouse->pktsize = 6;
1450 } else {
1451 /* Relative mode follows standard PS/2 mouse protocol */
1452 psmouse->protocol_handler = psmouse_process_byte;
1453 psmouse->pktsize = 3;
1454 }
1455
1386 psmouse->set_rate = synaptics_set_rate; 1456 psmouse->set_rate = synaptics_set_rate;
1387 psmouse->disconnect = synaptics_disconnect; 1457 psmouse->disconnect = synaptics_disconnect;
1388 psmouse->reconnect = synaptics_reconnect; 1458 psmouse->reconnect = synaptics_reconnect;
1389 psmouse->cleanup = synaptics_reset; 1459 psmouse->cleanup = synaptics_reset;
1390 psmouse->pktsize = 6;
1391 /* Synaptics can usually stay in sync without extra help */ 1460 /* Synaptics can usually stay in sync without extra help */
1392 psmouse->resync_time = 0; 1461 psmouse->resync_time = 0;
1393 1462
@@ -1406,11 +1475,32 @@ int synaptics_init(struct psmouse *psmouse)
1406 psmouse->rate = 40; 1475 psmouse->rate = 40;
1407 } 1476 }
1408 1477
1478 if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) {
1479 err = device_create_file(&psmouse->ps2dev.serio->dev,
1480 &psmouse_attr_disable_gesture.dattr);
1481 if (err) {
1482 psmouse_err(psmouse,
1483 "Failed to create disable_gesture attribute (%d)",
1484 err);
1485 goto init_fail;
1486 }
1487 }
1488
1409 return 0; 1489 return 0;
1410 1490
1411 init_fail: 1491 init_fail:
1412 kfree(priv); 1492 kfree(priv);
1413 return -1; 1493 return err;
1494}
1495
1496int synaptics_init(struct psmouse *psmouse)
1497{
1498 return __synaptics_init(psmouse, true);
1499}
1500
1501int synaptics_init_relative(struct psmouse *psmouse)
1502{
1503 return __synaptics_init(psmouse, false);
1414} 1504}
1415 1505
1416bool synaptics_supported(void) 1506bool synaptics_supported(void)
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 622aea8dd7e0..fd26ccca13d7 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -100,6 +100,7 @@
100#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) 100#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
101#define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i)) 101#define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i))
102#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) 102#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
103#define SYN_ID_DISGEST_SUPPORTED(i) (SYN_ID_MAJOR(i) >= 4)
103 104
104/* synaptics special commands */ 105/* synaptics special commands */
105#define SYN_PS_SET_MODE2 0x14 106#define SYN_PS_SET_MODE2 0x14
@@ -159,6 +160,9 @@ struct synaptics_data {
159 unsigned char mode; /* current mode byte */ 160 unsigned char mode; /* current mode byte */
160 int scroll; 161 int scroll;
161 162
163 bool absolute_mode; /* run in Absolute mode */
164 bool disable_gesture; /* disable gestures */
165
162 struct serio *pt_port; /* Pass-through serio port */ 166 struct serio *pt_port; /* Pass-through serio port */
163 167
164 struct synaptics_mt_state mt_state; /* Current mt finger state */ 168 struct synaptics_mt_state mt_state; /* Current mt finger state */
@@ -175,6 +179,7 @@ struct synaptics_data {
175void synaptics_module_init(void); 179void synaptics_module_init(void);
176int synaptics_detect(struct psmouse *psmouse, bool set_properties); 180int synaptics_detect(struct psmouse *psmouse, bool set_properties);
177int synaptics_init(struct psmouse *psmouse); 181int synaptics_init(struct psmouse *psmouse);
182int synaptics_init_relative(struct psmouse *psmouse);
178void synaptics_reset(struct psmouse *psmouse); 183void synaptics_reset(struct psmouse *psmouse);
179bool synaptics_supported(void); 184bool synaptics_supported(void);
180 185