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

Input: trackpoint - Optimize trackpoint init to use power-on reset

The trackpoint driver sets various parameter default values, all of
which happen to be power-on defaults (Source: IBM TrackPoint Engineering
Specification, Version 4.0. Also confirmed by empirical data).

By sending the power-on reset command to reset all parameters to
power-on state, we can skip the lengthy process of programming all
parameters. In testing, ~2.5 secs of time writing parameters was reduced
to .35 seconds waiting for power-on reset to complete.

Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Shawn Nematbakhsh and committed by
Dmitry Torokhov
0c6a6165 e07a8943

+162 -83
+159 -82
drivers/input/mouse/trackpoint.c
··· 20 20 #include "trackpoint.h" 21 21 22 22 /* 23 + * Power-on Reset: Resets all trackpoint parameters, including RAM values, 24 + * to defaults. 25 + * Returns zero on success, non-zero on failure. 26 + */ 27 + static int trackpoint_power_on_reset(struct ps2dev *ps2dev) 28 + { 29 + unsigned char results[2]; 30 + int tries = 0; 31 + 32 + /* Issue POR command, and repeat up to once if 0xFC00 received */ 33 + do { 34 + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 35 + ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR))) 36 + return -1; 37 + } while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2); 38 + 39 + /* Check for success response -- 0xAA00 */ 40 + if (results[0] != 0xAA || results[1] != 0x00) 41 + return -1; 42 + 43 + return 0; 44 + } 45 + 46 + /* 23 47 * Device IO: read, write and toggle bit 24 48 */ 25 - static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results) 49 + static int trackpoint_read(struct ps2dev *ps2dev, 50 + unsigned char loc, unsigned char *results) 26 51 { 27 52 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 28 53 ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { ··· 57 32 return 0; 58 33 } 59 34 60 - static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val) 35 + static int trackpoint_write(struct ps2dev *ps2dev, 36 + unsigned char loc, unsigned char val) 61 37 { 62 38 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 63 39 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || ··· 70 44 return 0; 71 45 } 72 46 73 - static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask) 47 + static int trackpoint_toggle_bit(struct ps2dev *ps2dev, 48 + unsigned char loc, unsigned char mask) 74 49 { 75 50 /* Bad things will happen if the loc param isn't in this range */ 76 51 if (loc < 0x20 || loc >= 0x2F) ··· 87 60 return 0; 88 61 } 89 62 63 + static int trackpoint_update_bit(struct ps2dev *ps2dev, unsigned char loc, 64 + unsigned char mask, unsigned char value) 65 + { 66 + int retval = 0; 67 + unsigned char data; 68 + 69 + trackpoint_read(ps2dev, loc, &data); 70 + if (((data & mask) == mask) != !!value) 71 + retval = trackpoint_toggle_bit(ps2dev, loc, mask); 72 + 73 + return retval; 74 + } 90 75 91 76 /* 92 77 * Trackpoint-specific attributes ··· 108 69 unsigned char command; 109 70 unsigned char mask; 110 71 unsigned char inverted; 72 + unsigned char power_on_default; 111 73 }; 112 74 113 75 static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf) ··· 142 102 return count; 143 103 } 144 104 145 - #define TRACKPOINT_INT_ATTR(_name, _command) \ 105 + #define TRACKPOINT_INT_ATTR(_name, _command, _default) \ 146 106 static struct trackpoint_attr_data trackpoint_attr_##_name = { \ 147 107 .field_offset = offsetof(struct trackpoint_data, _name), \ 148 108 .command = _command, \ 109 + .power_on_default = _default, \ 149 110 }; \ 150 111 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 151 112 &trackpoint_attr_##_name, \ ··· 180 139 } 181 140 182 141 183 - #define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv) \ 184 - static struct trackpoint_attr_data trackpoint_attr_##_name = { \ 185 - .field_offset = offsetof(struct trackpoint_data, _name), \ 186 - .command = _command, \ 187 - .mask = _mask, \ 188 - .inverted = _inv, \ 189 - }; \ 190 - PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 191 - &trackpoint_attr_##_name, \ 192 - trackpoint_show_int_attr, trackpoint_set_bit_attr) 142 + #define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv, _default) \ 143 + static struct trackpoint_attr_data trackpoint_attr_##_name = { \ 144 + .field_offset = offsetof(struct trackpoint_data, \ 145 + _name), \ 146 + .command = _command, \ 147 + .mask = _mask, \ 148 + .inverted = _inv, \ 149 + .power_on_default = _default, \ 150 + }; \ 151 + PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 152 + &trackpoint_attr_##_name, \ 153 + trackpoint_show_int_attr, trackpoint_set_bit_attr) 193 154 194 - TRACKPOINT_INT_ATTR(sensitivity, TP_SENS); 195 - TRACKPOINT_INT_ATTR(speed, TP_SPEED); 196 - TRACKPOINT_INT_ATTR(inertia, TP_INERTIA); 197 - TRACKPOINT_INT_ATTR(reach, TP_REACH); 198 - TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS); 199 - TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG); 200 - TRACKPOINT_INT_ATTR(thresh, TP_THRESH); 201 - TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH); 202 - TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME); 203 - TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV); 155 + #define TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name) \ 156 + do { \ 157 + struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \ 158 + \ 159 + trackpoint_update_bit(&_psmouse->ps2dev, \ 160 + _attr->command, _attr->mask, _tp->_name); \ 161 + } while (0) 204 162 205 - TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0); 206 - TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0); 207 - TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1); 163 + #define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \ 164 + do { \ 165 + if (!_power_on || \ 166 + _tp->_name != trackpoint_attr_##_name.power_on_default) { \ 167 + if (!trackpoint_attr_##_name.mask) \ 168 + trackpoint_write(&_psmouse->ps2dev, \ 169 + trackpoint_attr_##_name.command, \ 170 + _tp->_name); \ 171 + else \ 172 + TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name); \ 173 + } \ 174 + } while (0) 175 + 176 + #define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \ 177 + (_tp->_name = trackpoint_attr_##_name.power_on_default) 178 + 179 + TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS); 180 + TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED); 181 + TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA); 182 + TRACKPOINT_INT_ATTR(reach, TP_REACH, TP_DEF_REACH); 183 + TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS, TP_DEF_DRAGHYS); 184 + TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG, TP_DEF_MINDRAG); 185 + TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH); 186 + TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH); 187 + TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME); 188 + TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV); 189 + 190 + TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0, 191 + TP_DEF_PTSON); 192 + TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0, 193 + TP_DEF_SKIPBACK); 194 + TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1, 195 + TP_DEF_EXT_DEV); 208 196 209 197 static struct attribute *trackpoint_attrs[] = { 210 198 &psmouse_attr_sensitivity.dattr.attr, ··· 272 202 return 0; 273 203 } 274 204 275 - static int trackpoint_sync(struct psmouse *psmouse) 205 + /* 206 + * Write parameters to trackpad. 207 + * in_power_on_state: Set to true if TP is in default / power-on state (ex. if 208 + * power-on reset was run). If so, values will only be 209 + * written to TP if they differ from power-on default. 210 + */ 211 + static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state) 276 212 { 277 213 struct trackpoint_data *tp = psmouse->private; 278 - unsigned char toggle; 279 214 280 - /* Disable features that may make device unusable with this driver */ 281 - trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle); 282 - if (toggle & TP_MASK_TWOHAND) 283 - trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND); 215 + if (!in_power_on_state) { 216 + /* 217 + * Disable features that may make device unusable 218 + * with this driver. 219 + */ 220 + trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, 221 + TP_MASK_TWOHAND, TP_DEF_TWOHAND); 284 222 285 - trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle); 286 - if (toggle & TP_MASK_SOURCE_TAG) 287 - trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG); 223 + trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, 224 + TP_MASK_SOURCE_TAG, TP_DEF_SOURCE_TAG); 288 225 289 - trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle); 290 - if (toggle & TP_MASK_MB) 291 - trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB); 226 + trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_MB, 227 + TP_MASK_MB, TP_DEF_MB); 228 + } 292 229 293 - /* Push the config to the device */ 294 - trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity); 295 - trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia); 296 - trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed); 230 + /* 231 + * These properties can be changed in this driver. Only 232 + * configure them if the values are non-default or if the TP is in 233 + * an unknown state. 234 + */ 235 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, sensitivity); 236 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, inertia); 237 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, speed); 238 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, reach); 239 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, draghys); 240 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, mindrag); 241 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, thresh); 242 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh); 243 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime); 244 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks); 297 245 298 - trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach); 299 - trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys); 300 - trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag); 301 - 302 - trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh); 303 - trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh); 304 - 305 - trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime); 306 - trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks); 307 - 308 - trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle); 309 - if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select) 310 - trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON); 311 - 312 - trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle); 313 - if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback) 314 - trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); 315 - 316 - trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle); 317 - if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev) 318 - trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); 246 + /* toggles */ 247 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select); 248 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, skipback); 249 + TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ext_dev); 319 250 320 251 return 0; 321 252 } 322 253 323 254 static void trackpoint_defaults(struct trackpoint_data *tp) 324 255 { 325 - tp->press_to_select = TP_DEF_PTSON; 326 - tp->sensitivity = TP_DEF_SENS; 327 - tp->speed = TP_DEF_SPEED; 328 - tp->reach = TP_DEF_REACH; 256 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, sensitivity); 257 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, speed); 258 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, reach); 259 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, draghys); 260 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, mindrag); 261 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, thresh); 262 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh); 263 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime); 264 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks); 265 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia); 329 266 330 - tp->draghys = TP_DEF_DRAGHYS; 331 - tp->mindrag = TP_DEF_MINDRAG; 332 - 333 - tp->thresh = TP_DEF_THRESH; 334 - tp->upthresh = TP_DEF_UP_THRESH; 335 - 336 - tp->ztime = TP_DEF_Z_TIME; 337 - tp->jenks = TP_DEF_JENKS_CURV; 338 - 339 - tp->inertia = TP_DEF_INERTIA; 340 - tp->skipback = TP_DEF_SKIPBACK; 341 - tp->ext_dev = TP_DEF_EXT_DEV; 267 + /* toggles */ 268 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, press_to_select); 269 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, skipback); 270 + TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ext_dev); 342 271 } 343 272 344 273 static void trackpoint_disconnect(struct psmouse *psmouse) ··· 350 281 351 282 static int trackpoint_reconnect(struct psmouse *psmouse) 352 283 { 284 + int reset_fail; 285 + 353 286 if (trackpoint_start_protocol(psmouse, NULL)) 354 287 return -1; 355 288 356 - if (trackpoint_sync(psmouse)) 289 + reset_fail = trackpoint_power_on_reset(&psmouse->ps2dev); 290 + if (trackpoint_sync(psmouse, !reset_fail)) 357 291 return -1; 358 292 359 293 return 0; ··· 394 322 __set_bit(BTN_MIDDLE, psmouse->dev->keybit); 395 323 396 324 trackpoint_defaults(psmouse->private); 397 - trackpoint_sync(psmouse); 325 + 326 + error = trackpoint_power_on_reset(&psmouse->ps2dev); 327 + 328 + /* Write defaults to TP only if reset fails. */ 329 + if (error) 330 + trackpoint_sync(psmouse, false); 398 331 399 332 error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); 400 333 if (error) {
+3 -1
drivers/input/mouse/trackpoint.h
··· 126 126 #define TP_DEF_PTSON 0x00 127 127 #define TP_DEF_SKIPBACK 0x00 128 128 #define TP_DEF_EXT_DEV 0x00 /* 0 means enabled */ 129 + #define TP_DEF_TWOHAND 0x00 130 + #define TP_DEF_SOURCE_TAG 0x00 129 131 130 132 #define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) 131 133 ··· 138 136 unsigned char thresh, upthresh; 139 137 unsigned char ztime, jenks; 140 138 139 + /* toggles */ 141 140 unsigned char press_to_select; 142 141 unsigned char skipback; 143 - 144 142 unsigned char ext_dev; 145 143 }; 146 144