aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2013-04-15 16:49:34 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-04-19 12:05:44 -0400
commit0c6a61657da78098472fd0eb71cc01f2387fa1bb (patch)
treeb4d9cd085eaae625a3231edd1c5e64a9370ecd17 /drivers/input/mouse
parente07a8943b809730220a4aff911d2bce6991828f1 (diff)
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>
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r--drivers/input/mouse/trackpoint.c249
-rw-r--r--drivers/input/mouse/trackpoint.h4
2 files changed, 166 insertions, 87 deletions
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index f3102494237d..ca843b6cf6bd 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -20,9 +20,34 @@
20#include "trackpoint.h" 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 */
27static 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 * Device IO: read, write and toggle bit 47 * Device IO: read, write and toggle bit
24 */ 48 */
25static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results) 49static int trackpoint_read(struct ps2dev *ps2dev,
50 unsigned char loc, unsigned char *results)
26{ 51{
27 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 52 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
28 ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { 53 ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
@@ -32,7 +57,8 @@ static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned ch
32 return 0; 57 return 0;
33} 58}
34 59
35static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val) 60static int trackpoint_write(struct ps2dev *ps2dev,
61 unsigned char loc, unsigned char val)
36{ 62{
37 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 63 if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
38 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || 64 ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
@@ -44,7 +70,8 @@ static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned c
44 return 0; 70 return 0;
45} 71}
46 72
47static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask) 73static int trackpoint_toggle_bit(struct ps2dev *ps2dev,
74 unsigned char loc, unsigned char mask)
48{ 75{
49 /* Bad things will happen if the loc param isn't in this range */ 76 /* Bad things will happen if the loc param isn't in this range */
50 if (loc < 0x20 || loc >= 0x2F) 77 if (loc < 0x20 || loc >= 0x2F)
@@ -60,6 +87,18 @@ static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsig
60 return 0; 87 return 0;
61} 88}
62 89
90static int trackpoint_update_bit(struct ps2dev *ps2dev, unsigned char loc,
91 unsigned char mask, unsigned char value)
92{
93 int retval = 0;
94 unsigned char data;
95
96 trackpoint_read(ps2dev, loc, &data);
97 if (((data & mask) == mask) != !!value)
98 retval = trackpoint_toggle_bit(ps2dev, loc, mask);
99
100 return retval;
101}
63 102
64/* 103/*
65 * Trackpoint-specific attributes 104 * Trackpoint-specific attributes
@@ -69,6 +108,7 @@ struct trackpoint_attr_data {
69 unsigned char command; 108 unsigned char command;
70 unsigned char mask; 109 unsigned char mask;
71 unsigned char inverted; 110 unsigned char inverted;
111 unsigned char power_on_default;
72}; 112};
73 113
74static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf) 114static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf)
@@ -102,10 +142,11 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
102 return count; 142 return count;
103} 143}
104 144
105#define TRACKPOINT_INT_ATTR(_name, _command) \ 145#define TRACKPOINT_INT_ATTR(_name, _command, _default) \
106 static struct trackpoint_attr_data trackpoint_attr_##_name = { \ 146 static struct trackpoint_attr_data trackpoint_attr_##_name = { \
107 .field_offset = offsetof(struct trackpoint_data, _name), \ 147 .field_offset = offsetof(struct trackpoint_data, _name), \
108 .command = _command, \ 148 .command = _command, \
149 .power_on_default = _default, \
109 }; \ 150 }; \
110 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 151 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
111 &trackpoint_attr_##_name, \ 152 &trackpoint_attr_##_name, \
@@ -139,31 +180,60 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
139} 180}
140 181
141 182
142#define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv) \ 183#define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv, _default) \
143 static struct trackpoint_attr_data trackpoint_attr_##_name = { \ 184static struct trackpoint_attr_data trackpoint_attr_##_name = { \
144 .field_offset = offsetof(struct trackpoint_data, _name), \ 185 .field_offset = offsetof(struct trackpoint_data, \
145 .command = _command, \ 186 _name), \
146 .mask = _mask, \ 187 .command = _command, \
147 .inverted = _inv, \ 188 .mask = _mask, \
148 }; \ 189 .inverted = _inv, \
149 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 190 .power_on_default = _default, \
150 &trackpoint_attr_##_name, \ 191 }; \
151 trackpoint_show_int_attr, trackpoint_set_bit_attr) 192PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
152 193 &trackpoint_attr_##_name, \
153TRACKPOINT_INT_ATTR(sensitivity, TP_SENS); 194 trackpoint_show_int_attr, trackpoint_set_bit_attr)
154TRACKPOINT_INT_ATTR(speed, TP_SPEED); 195
155TRACKPOINT_INT_ATTR(inertia, TP_INERTIA); 196#define TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name) \
156TRACKPOINT_INT_ATTR(reach, TP_REACH); 197do { \
157TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS); 198 struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \
158TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG); 199 \
159TRACKPOINT_INT_ATTR(thresh, TP_THRESH); 200 trackpoint_update_bit(&_psmouse->ps2dev, \
160TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH); 201 _attr->command, _attr->mask, _tp->_name); \
161TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME); 202} while (0)
162TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV); 203
163 204#define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \
164TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0); 205do { \
165TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0); 206 if (!_power_on || \
166TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1); 207 _tp->_name != trackpoint_attr_##_name.power_on_default) { \
208 if (!trackpoint_attr_##_name.mask) \
209 trackpoint_write(&_psmouse->ps2dev, \
210 trackpoint_attr_##_name.command, \
211 _tp->_name); \
212 else \
213 TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name); \
214 } \
215} while (0)
216
217#define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \
218 (_tp->_name = trackpoint_attr_##_name.power_on_default)
219
220TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS);
221TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED);
222TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA);
223TRACKPOINT_INT_ATTR(reach, TP_REACH, TP_DEF_REACH);
224TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS, TP_DEF_DRAGHYS);
225TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG, TP_DEF_MINDRAG);
226TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH);
227TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH);
228TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME);
229TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV);
230
231TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0,
232 TP_DEF_PTSON);
233TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0,
234 TP_DEF_SKIPBACK);
235TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1,
236 TP_DEF_EXT_DEV);
167 237
168static struct attribute *trackpoint_attrs[] = { 238static struct attribute *trackpoint_attrs[] = {
169 &psmouse_attr_sensitivity.dattr.attr, 239 &psmouse_attr_sensitivity.dattr.attr,
@@ -202,73 +272,72 @@ static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *fir
202 return 0; 272 return 0;
203} 273}
204 274
205static int trackpoint_sync(struct psmouse *psmouse) 275/*
276 * Write parameters to trackpad.
277 * in_power_on_state: Set to true if TP is in default / power-on state (ex. if
278 * power-on reset was run). If so, values will only be
279 * written to TP if they differ from power-on default.
280 */
281static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state)
206{ 282{
207 struct trackpoint_data *tp = psmouse->private; 283 struct trackpoint_data *tp = psmouse->private;
208 unsigned char toggle;
209
210 /* Disable features that may make device unusable with this driver */
211 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle);
212 if (toggle & TP_MASK_TWOHAND)
213 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND);
214
215 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle);
216 if (toggle & TP_MASK_SOURCE_TAG)
217 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG);
218
219 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle);
220 if (toggle & TP_MASK_MB)
221 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB);
222
223 /* Push the config to the device */
224 trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity);
225 trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia);
226 trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed);
227
228 trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach);
229 trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys);
230 trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag);
231
232 trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh);
233 trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh);
234 284
235 trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime); 285 if (!in_power_on_state) {
236 trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks); 286 /*
287 * Disable features that may make device unusable
288 * with this driver.
289 */
290 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND,
291 TP_MASK_TWOHAND, TP_DEF_TWOHAND);
237 292
238 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle); 293 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG,
239 if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select) 294 TP_MASK_SOURCE_TAG, TP_DEF_SOURCE_TAG);
240 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON);
241 295
242 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle); 296 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_MB,
243 if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback) 297 TP_MASK_MB, TP_DEF_MB);
244 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); 298 }
245 299
246 trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle); 300 /*
247 if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev) 301 * These properties can be changed in this driver. Only
248 trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); 302 * configure them if the values are non-default or if the TP is in
303 * an unknown state.
304 */
305 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, sensitivity);
306 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, inertia);
307 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, speed);
308 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, reach);
309 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, draghys);
310 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, mindrag);
311 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, thresh);
312 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh);
313 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime);
314 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks);
315
316 /* toggles */
317 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select);
318 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, skipback);
319 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ext_dev);
249 320
250 return 0; 321 return 0;
251} 322}
252 323
253static void trackpoint_defaults(struct trackpoint_data *tp) 324static void trackpoint_defaults(struct trackpoint_data *tp)
254{ 325{
255 tp->press_to_select = TP_DEF_PTSON; 326 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, sensitivity);
256 tp->sensitivity = TP_DEF_SENS; 327 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, speed);
257 tp->speed = TP_DEF_SPEED; 328 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, reach);
258 tp->reach = TP_DEF_REACH; 329 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, draghys);
259 330 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, mindrag);
260 tp->draghys = TP_DEF_DRAGHYS; 331 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, thresh);
261 tp->mindrag = TP_DEF_MINDRAG; 332 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh);
262 333 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime);
263 tp->thresh = TP_DEF_THRESH; 334 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks);
264 tp->upthresh = TP_DEF_UP_THRESH; 335 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia);
265 336
266 tp->ztime = TP_DEF_Z_TIME; 337 /* toggles */
267 tp->jenks = TP_DEF_JENKS_CURV; 338 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, press_to_select);
268 339 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, skipback);
269 tp->inertia = TP_DEF_INERTIA; 340 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ext_dev);
270 tp->skipback = TP_DEF_SKIPBACK;
271 tp->ext_dev = TP_DEF_EXT_DEV;
272} 341}
273 342
274static void trackpoint_disconnect(struct psmouse *psmouse) 343static void trackpoint_disconnect(struct psmouse *psmouse)
@@ -281,10 +350,13 @@ static void trackpoint_disconnect(struct psmouse *psmouse)
281 350
282static int trackpoint_reconnect(struct psmouse *psmouse) 351static int trackpoint_reconnect(struct psmouse *psmouse)
283{ 352{
353 int reset_fail;
354
284 if (trackpoint_start_protocol(psmouse, NULL)) 355 if (trackpoint_start_protocol(psmouse, NULL))
285 return -1; 356 return -1;
286 357
287 if (trackpoint_sync(psmouse)) 358 reset_fail = trackpoint_power_on_reset(&psmouse->ps2dev);
359 if (trackpoint_sync(psmouse, !reset_fail))
288 return -1; 360 return -1;
289 361
290 return 0; 362 return 0;
@@ -322,7 +394,12 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
322 __set_bit(BTN_MIDDLE, psmouse->dev->keybit); 394 __set_bit(BTN_MIDDLE, psmouse->dev->keybit);
323 395
324 trackpoint_defaults(psmouse->private); 396 trackpoint_defaults(psmouse->private);
325 trackpoint_sync(psmouse); 397
398 error = trackpoint_power_on_reset(&psmouse->ps2dev);
399
400 /* Write defaults to TP only if reset fails. */
401 if (error)
402 trackpoint_sync(psmouse, false);
326 403
327 error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); 404 error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
328 if (error) { 405 if (error) {
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index e558a7096618..ecd0547964a5 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -126,6 +126,8 @@
126#define TP_DEF_PTSON 0x00 126#define TP_DEF_PTSON 0x00
127#define TP_DEF_SKIPBACK 0x00 127#define TP_DEF_SKIPBACK 0x00
128#define TP_DEF_EXT_DEV 0x00 /* 0 means enabled */ 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#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) 132#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
131 133
@@ -136,9 +138,9 @@ struct trackpoint_data
136 unsigned char thresh, upthresh; 138 unsigned char thresh, upthresh;
137 unsigned char ztime, jenks; 139 unsigned char ztime, jenks;
138 140
141 /* toggles */
139 unsigned char press_to_select; 142 unsigned char press_to_select;
140 unsigned char skipback; 143 unsigned char skipback;
141
142 unsigned char ext_dev; 144 unsigned char ext_dev;
143}; 145};
144 146