Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Daniel Drake and committed by
Dmitry Torokhov
7968a5dd 76496e7a

+152 -48
+8 -1
drivers/input/mouse/psmouse-base.c
··· 127 127 * relevant events to the input module once full packet has arrived. 128 128 */ 129 129 130 - static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) 130 + psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) 131 131 { 132 132 struct input_dev *dev = psmouse->dev; 133 133 unsigned char *packet = psmouse->packet; ··· 818 818 .alias = "synaptics", 819 819 .detect = synaptics_detect, 820 820 .init = synaptics_init, 821 + }, 822 + { 823 + .type = PSMOUSE_SYNAPTICS_RELATIVE, 824 + .name = "SynRelPS/2", 825 + .alias = "synaptics-relative", 826 + .detect = synaptics_detect, 827 + .init = synaptics_init_relative, 821 828 }, 822 829 #endif 823 830 #ifdef CONFIG_MOUSE_PS2_ALPS
+2
drivers/input/mouse/psmouse.h
··· 94 94 PSMOUSE_HGPK, 95 95 PSMOUSE_ELANTECH, 96 96 PSMOUSE_FSP, 97 + PSMOUSE_SYNAPTICS_RELATIVE, 97 98 PSMOUSE_AUTO /* This one should always be last */ 98 99 }; 99 100 ··· 104 103 int psmouse_reset(struct psmouse *psmouse); 105 104 void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); 106 105 void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); 106 + psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); 107 107 108 108 struct psmouse_attribute { 109 109 struct device_attribute dattr;
+137 -47
drivers/input/mouse/synaptics.c
··· 268 268 return 0; 269 269 } 270 270 271 - static int synaptics_set_absolute_mode(struct psmouse *psmouse) 271 + static 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 + 291 + static int synaptics_set_mode(struct psmouse *psmouse) 272 292 { 273 293 struct synaptics_data *priv = psmouse->private; 274 294 275 - priv->mode = SYN_BIT_ABSOLUTE_MODE; 276 - if (SYN_ID_MAJOR(priv->identity) >= 4) 295 + priv->mode = 0; 296 + if (priv->absolute_mode) 297 + priv->mode |= SYN_BIT_ABSOLUTE_MODE; 298 + if (priv->disable_gesture) 277 299 priv->mode |= SYN_BIT_DISABLE_GESTURE; 300 + if (psmouse->rate >= 80) 301 + priv->mode |= SYN_BIT_HIGH_RATE; 278 302 if (SYN_CAP_EXTENDED(priv->capabilities)) 279 303 priv->mode |= SYN_BIT_W_MODE; 280 304 281 305 if (synaptics_mode_cmd(psmouse, priv->mode)) 282 306 return -1; 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 + } 283 313 284 314 return 0; 285 315 } ··· 327 297 } 328 298 329 299 synaptics_mode_cmd(psmouse, priv->mode); 330 - } 331 - 332 - static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) 333 - { 334 - static unsigned char param = 0xc8; 335 - struct synaptics_data *priv = psmouse->private; 336 - 337 - if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || 338 - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))) 339 - return 0; 340 - 341 - if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) 342 - return -1; 343 - if (ps2_command(&psmouse->ps2dev, &param, PSMOUSE_CMD_SETRATE)) 344 - return -1; 345 - 346 - /* Advanced gesture mode also sends multi finger data */ 347 - priv->capabilities |= BIT(1); 348 - 349 - return 0; 350 300 } 351 301 352 302 /***************************************************************************** ··· 1152 1142 { 1153 1143 int i; 1154 1144 1145 + /* Things that apply to both modes */ 1155 1146 __set_bit(INPUT_PROP_POINTER, dev->propbit); 1147 + __set_bit(EV_KEY, dev->evbit); 1148 + __set_bit(BTN_LEFT, dev->keybit); 1149 + __set_bit(BTN_RIGHT, dev->keybit); 1156 1150 1151 + if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) 1152 + __set_bit(BTN_MIDDLE, dev->keybit); 1153 + 1154 + if (!priv->absolute_mode) { 1155 + /* Relative mode */ 1156 + __set_bit(EV_REL, dev->evbit); 1157 + __set_bit(REL_X, dev->relbit); 1158 + __set_bit(REL_Y, dev->relbit); 1159 + return; 1160 + } 1161 + 1162 + /* Absolute mode */ 1157 1163 __set_bit(EV_ABS, dev->evbit); 1158 1164 set_abs_position_params(dev, priv, ABS_X, ABS_Y); 1159 1165 input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); ··· 1195 1169 if (SYN_CAP_PALMDETECT(priv->capabilities)) 1196 1170 input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); 1197 1171 1198 - __set_bit(EV_KEY, dev->evbit); 1199 1172 __set_bit(BTN_TOUCH, dev->keybit); 1200 1173 __set_bit(BTN_TOOL_FINGER, dev->keybit); 1201 - __set_bit(BTN_LEFT, dev->keybit); 1202 - __set_bit(BTN_RIGHT, dev->keybit); 1203 1174 1204 1175 if (SYN_CAP_MULTIFINGER(priv->capabilities)) { 1205 1176 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); 1206 1177 __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); 1207 1178 } 1208 - 1209 - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) 1210 - __set_bit(BTN_MIDDLE, dev->keybit); 1211 1179 1212 1180 if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || 1213 1181 SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { ··· 1224 1204 } 1225 1205 } 1226 1206 1207 + static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse, 1208 + void *data, char *buf) 1209 + { 1210 + struct synaptics_data *priv = psmouse->private; 1211 + 1212 + return sprintf(buf, "%c\n", priv->disable_gesture ? '1' : '0'); 1213 + } 1214 + 1215 + static ssize_t synaptics_set_disable_gesture(struct psmouse *psmouse, 1216 + void *data, const char *buf, 1217 + size_t len) 1218 + { 1219 + struct synaptics_data *priv = psmouse->private; 1220 + unsigned int value; 1221 + int err; 1222 + 1223 + err = kstrtouint(buf, 10, &value); 1224 + if (err) 1225 + return err; 1226 + 1227 + if (value > 1) 1228 + return -EINVAL; 1229 + 1230 + if (value == priv->disable_gesture) 1231 + return len; 1232 + 1233 + priv->disable_gesture = value; 1234 + if (value) 1235 + priv->mode |= SYN_BIT_DISABLE_GESTURE; 1236 + else 1237 + priv->mode &= ~SYN_BIT_DISABLE_GESTURE; 1238 + 1239 + if (synaptics_mode_cmd(psmouse, priv->mode)) 1240 + return -EIO; 1241 + 1242 + return len; 1243 + } 1244 + 1245 + PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL, 1246 + synaptics_show_disable_gesture, 1247 + synaptics_set_disable_gesture); 1248 + 1227 1249 static void synaptics_disconnect(struct psmouse *psmouse) 1228 1250 { 1251 + struct synaptics_data *priv = psmouse->private; 1252 + 1253 + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) 1254 + device_remove_file(&psmouse->ps2dev.serio->dev, 1255 + &psmouse_attr_disable_gesture.dattr); 1256 + 1229 1257 synaptics_reset(psmouse); 1230 - kfree(psmouse->private); 1258 + kfree(priv); 1231 1259 psmouse->private = NULL; 1232 1260 } 1233 1261 ··· 1302 1234 return -1; 1303 1235 } 1304 1236 1305 - if (synaptics_set_absolute_mode(psmouse)) { 1237 + if (synaptics_set_mode(psmouse)) { 1306 1238 psmouse_err(psmouse, "Unable to initialize device.\n"); 1307 - return -1; 1308 - } 1309 - 1310 - if (synaptics_set_advanced_gesture_mode(psmouse)) { 1311 - psmouse_err(psmouse, 1312 - "Advanced gesture mode reconnect failed.\n"); 1313 1239 return -1; 1314 1240 } 1315 1241 ··· 1383 1321 broken_olpc_ec = dmi_check_system(olpc_dmi_table); 1384 1322 } 1385 1323 1386 - int synaptics_init(struct psmouse *psmouse) 1324 + static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) 1387 1325 { 1388 1326 struct synaptics_data *priv; 1327 + int err = -1; 1389 1328 1390 1329 /* 1391 1330 * The OLPC XO has issues with Synaptics' absolute mode; similarly to ··· 1414 1351 goto init_fail; 1415 1352 } 1416 1353 1417 - if (synaptics_set_absolute_mode(psmouse)) { 1418 - psmouse_err(psmouse, "Unable to initialize device.\n"); 1419 - goto init_fail; 1420 - } 1354 + priv->absolute_mode = absolute_mode; 1355 + if (SYN_ID_DISGEST_SUPPORTED(priv->identity)) 1356 + priv->disable_gesture = true; 1421 1357 1422 - if (synaptics_set_advanced_gesture_mode(psmouse)) { 1423 - psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); 1358 + if (synaptics_set_mode(psmouse)) { 1359 + psmouse_err(psmouse, "Unable to initialize device.\n"); 1424 1360 goto init_fail; 1425 1361 } 1426 1362 ··· 1444 1382 psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) | 1445 1383 (priv->model_id & 0x000000ff); 1446 1384 1447 - psmouse->protocol_handler = synaptics_process_byte; 1385 + if (absolute_mode) { 1386 + psmouse->protocol_handler = synaptics_process_byte; 1387 + psmouse->pktsize = 6; 1388 + } else { 1389 + /* Relative mode follows standard PS/2 mouse protocol */ 1390 + psmouse->protocol_handler = psmouse_process_byte; 1391 + psmouse->pktsize = 3; 1392 + } 1393 + 1448 1394 psmouse->set_rate = synaptics_set_rate; 1449 1395 psmouse->disconnect = synaptics_disconnect; 1450 1396 psmouse->reconnect = synaptics_reconnect; 1451 1397 psmouse->cleanup = synaptics_reset; 1452 - psmouse->pktsize = 6; 1453 1398 /* Synaptics can usually stay in sync without extra help */ 1454 1399 psmouse->resync_time = 0; 1455 1400 ··· 1475 1406 psmouse->rate = 40; 1476 1407 } 1477 1408 1409 + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) { 1410 + err = device_create_file(&psmouse->ps2dev.serio->dev, 1411 + &psmouse_attr_disable_gesture.dattr); 1412 + if (err) { 1413 + psmouse_err(psmouse, 1414 + "Failed to create disable_gesture attribute (%d)", 1415 + err); 1416 + goto init_fail; 1417 + } 1418 + } 1419 + 1478 1420 return 0; 1479 1421 1480 1422 init_fail: 1481 1423 kfree(priv); 1482 - return -1; 1424 + return err; 1425 + } 1426 + 1427 + int synaptics_init(struct psmouse *psmouse) 1428 + { 1429 + return __synaptics_init(psmouse, true); 1430 + } 1431 + 1432 + int synaptics_init_relative(struct psmouse *psmouse) 1433 + { 1434 + return __synaptics_init(psmouse, false); 1483 1435 } 1484 1436 1485 1437 bool synaptics_supported(void)
+5
drivers/input/mouse/synaptics.h
··· 100 100 #define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) 101 101 #define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i)) 102 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 105 /* synaptics special commands */ 105 106 #define SYN_PS_SET_MODE2 0x14 ··· 160 159 unsigned char mode; /* current mode byte */ 161 160 int scroll; 162 161 162 + bool absolute_mode; /* run in Absolute mode */ 163 + bool disable_gesture; /* disable gestures */ 164 + 163 165 struct serio *pt_port; /* Pass-through serio port */ 164 166 165 167 struct synaptics_mt_state mt_state; /* Current mt finger state */ ··· 179 175 void synaptics_module_init(void); 180 176 int synaptics_detect(struct psmouse *psmouse, bool set_properties); 181 177 int synaptics_init(struct psmouse *psmouse); 178 + int synaptics_init_relative(struct psmouse *psmouse); 182 179 void synaptics_reset(struct psmouse *psmouse); 183 180 bool synaptics_supported(void); 184 181