1 /* 2 * Stephen Evanchik <evanchsa@gmail.com> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 as published by 6 * the Free Software Foundation. 7 * 8 * Trademarks are the property of their respective owners. 9 */ 10 11 #include <linux/slab.h> 12 #include <linux/delay.h> 13 #include <linux/serio.h> 14 #include <linux/module.h> 15 #include <linux/input.h> 16 #include <linux/libps2.h> 17 #include <linux/proc_fs.h> 18 #include <linux/uaccess.h> 19 #include "psmouse.h" 20 #include "trackpoint.h" 21 22 static const char * const trackpoint_variants[] = { 23 [TP_VARIANT_IBM] = "IBM", 24 [TP_VARIANT_ALPS] = "ALPS", 25 [TP_VARIANT_ELAN] = "Elan", 26 [TP_VARIANT_NXP] = "NXP", 27 }; 28 29 /* 30 * Power-on Reset: Resets all trackpoint parameters, including RAM values, 31 * to defaults. 32 * Returns zero on success, non-zero on failure. 33 */ 34 static int trackpoint_power_on_reset(struct ps2dev *ps2dev) 35 { 36 u8 param[2] = { TP_POR }; 37 int err; 38 39 err = ps2_command(ps2dev, param, MAKE_PS2_CMD(1, 2, TP_COMMAND)); 40 if (err) 41 return err; 42 43 /* Check for success response -- 0xAA00 */ 44 if (param[0] != 0xAA || param[1] != 0x00) 45 return -ENODEV; 46 47 return 0; 48 } 49 50 /* 51 * Device IO: read, write and toggle bit 52 */ 53 static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results) 54 { 55 results[0] = loc; 56 57 return ps2_command(ps2dev, results, MAKE_PS2_CMD(1, 1, TP_COMMAND)); 58 } 59 60 static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val) 61 { 62 u8 param[3] = { TP_WRITE_MEM, loc, val }; 63 64 return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND)); 65 } 66 67 static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask) 68 { 69 u8 param[3] = { TP_TOGGLE, loc, mask }; 70 71 /* Bad things will happen if the loc param isn't in this range */ 72 if (loc < 0x20 || loc >= 0x2F) 73 return -EINVAL; 74 75 return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND)); 76 } 77 78 static int trackpoint_update_bit(struct ps2dev *ps2dev, 79 u8 loc, u8 mask, u8 value) 80 { 81 int retval; 82 u8 data; 83 84 retval = trackpoint_read(ps2dev, loc, &data); 85 if (retval) 86 return retval; 87 88 if (((data & mask) == mask) != !!value) 89 retval = trackpoint_toggle_bit(ps2dev, loc, mask); 90 91 return retval; 92 } 93 94 /* 95 * Trackpoint-specific attributes 96 */ 97 struct trackpoint_attr_data { 98 size_t field_offset; 99 u8 command; 100 u8 mask; 101 bool inverted; 102 u8 power_on_default; 103 }; 104 105 static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, 106 void *data, char *buf) 107 { 108 struct trackpoint_data *tp = psmouse->private; 109 struct trackpoint_attr_data *attr = data; 110 u8 value = *(u8 *)((void *)tp + attr->field_offset); 111 112 if (attr->inverted) 113 value = !value; 114 115 return sprintf(buf, "%u\n", value); 116 } 117 118 static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data, 119 const char *buf, size_t count) 120 { 121 struct trackpoint_data *tp = psmouse->private; 122 struct trackpoint_attr_data *attr = data; 123 u8 *field = (void *)tp + attr->field_offset; 124 u8 value; 125 int err; 126 127 err = kstrtou8(buf, 10, &value); 128 if (err) 129 return err; 130 131 *field = value; 132 err = trackpoint_write(&psmouse->ps2dev, attr->command, value); 133 134 return err ?: count; 135 } 136 137 #define TRACKPOINT_INT_ATTR(_name, _command, _default) \ 138 static struct trackpoint_attr_data trackpoint_attr_##_name = { \ 139 .field_offset = offsetof(struct trackpoint_data, _name), \ 140 .command = _command, \ 141 .power_on_default = _default, \ 142 }; \ 143 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 144 &trackpoint_attr_##_name, \ 145 trackpoint_show_int_attr, trackpoint_set_int_attr) 146 147 static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data, 148 const char *buf, size_t count) 149 { 150 struct trackpoint_data *tp = psmouse->private; 151 struct trackpoint_attr_data *attr = data; 152 bool *field = (void *)tp + attr->field_offset; 153 bool value; 154 int err; 155 156 err = kstrtobool(buf, &value); 157 if (err) 158 return err; 159 160 if (attr->inverted) 161 value = !value; 162 163 if (*field != value) { 164 *field = value; 165 err = trackpoint_toggle_bit(&psmouse->ps2dev, 166 attr->command, attr->mask); 167 } 168 169 return err ?: count; 170 } 171 172 173 #define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv, _default) \ 174 static struct trackpoint_attr_data trackpoint_attr_##_name = { \ 175 .field_offset = offsetof(struct trackpoint_data, \ 176 _name), \ 177 .command = _command, \ 178 .mask = _mask, \ 179 .inverted = _inv, \ 180 .power_on_default = _default, \ 181 }; \ 182 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 183 &trackpoint_attr_##_name, \ 184 trackpoint_show_int_attr, trackpoint_set_bit_attr) 185 186 TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS); 187 TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED); 188 TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA); 189 TRACKPOINT_INT_ATTR(reach, TP_REACH, TP_DEF_REACH); 190 TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS, TP_DEF_DRAGHYS); 191 TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG, TP_DEF_MINDRAG); 192 TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH); 193 TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH); 194 TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME); 195 TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV); 196 TRACKPOINT_INT_ATTR(drift_time, TP_DRIFT_TIME, TP_DEF_DRIFT_TIME); 197 198 TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, false, 199 TP_DEF_PTSON); 200 TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, false, 201 TP_DEF_SKIPBACK); 202 TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, true, 203 TP_DEF_EXT_DEV); 204 205 static bool trackpoint_is_attr_available(struct psmouse *psmouse, 206 struct attribute *attr) 207 { 208 struct trackpoint_data *tp = psmouse->private; 209 210 return tp->variant_id == TP_VARIANT_IBM || 211 attr == &psmouse_attr_sensitivity.dattr.attr || 212 attr == &psmouse_attr_press_to_select.dattr.attr; 213 } 214 215 static umode_t trackpoint_is_attr_visible(struct kobject *kobj, 216 struct attribute *attr, int n) 217 { 218 struct device *dev = container_of(kobj, struct device, kobj); 219 struct serio *serio = to_serio_port(dev); 220 struct psmouse *psmouse = serio_get_drvdata(serio); 221 222 return trackpoint_is_attr_available(psmouse, attr) ? attr->mode : 0; 223 } 224 225 static struct attribute *trackpoint_attrs[] = { 226 &psmouse_attr_sensitivity.dattr.attr, 227 &psmouse_attr_speed.dattr.attr, 228 &psmouse_attr_inertia.dattr.attr, 229 &psmouse_attr_reach.dattr.attr, 230 &psmouse_attr_draghys.dattr.attr, 231 &psmouse_attr_mindrag.dattr.attr, 232 &psmouse_attr_thresh.dattr.attr, 233 &psmouse_attr_upthresh.dattr.attr, 234 &psmouse_attr_ztime.dattr.attr, 235 &psmouse_attr_jenks.dattr.attr, 236 &psmouse_attr_drift_time.dattr.attr, 237 &psmouse_attr_press_to_select.dattr.attr, 238 &psmouse_attr_skipback.dattr.attr, 239 &psmouse_attr_ext_dev.dattr.attr, 240 NULL 241 }; 242 243 static struct attribute_group trackpoint_attr_group = { 244 .is_visible = trackpoint_is_attr_visible, 245 .attrs = trackpoint_attrs, 246 }; 247 248 #define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \ 249 do { \ 250 struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \ 251 \ 252 if ((!_power_on || _tp->_name != _attr->power_on_default) && \ 253 trackpoint_is_attr_available(_psmouse, \ 254 &psmouse_attr_##_name.dattr.attr)) { \ 255 if (!_attr->mask) \ 256 trackpoint_write(&_psmouse->ps2dev, \ 257 _attr->command, _tp->_name); \ 258 else \ 259 trackpoint_update_bit(&_psmouse->ps2dev, \ 260 _attr->command, _attr->mask, \ 261 _tp->_name); \ 262 } \ 263 } while (0) 264 265 #define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \ 266 do { \ 267 _tp->_name = trackpoint_attr_##_name.power_on_default; \ 268 } while (0) 269 270 static int trackpoint_start_protocol(struct psmouse *psmouse, 271 u8 *variant_id, u8 *firmware_id) 272 { 273 u8 param[2] = { 0 }; 274 int error; 275 276 error = ps2_command(&psmouse->ps2dev, 277 param, MAKE_PS2_CMD(0, 2, TP_READ_ID)); 278 if (error) 279 return error; 280 281 switch (param[0]) { 282 case TP_VARIANT_IBM: 283 case TP_VARIANT_ALPS: 284 case TP_VARIANT_ELAN: 285 case TP_VARIANT_NXP: 286 if (variant_id) 287 *variant_id = param[0]; 288 if (firmware_id) 289 *firmware_id = param[1]; 290 return 0; 291 } 292 293 return -ENODEV; 294 } 295 296 /* 297 * Write parameters to trackpad. 298 * in_power_on_state: Set to true if TP is in default / power-on state (ex. if 299 * power-on reset was run). If so, values will only be 300 * written to TP if they differ from power-on default. 301 */ 302 static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state) 303 { 304 struct trackpoint_data *tp = psmouse->private; 305 306 if (!in_power_on_state && tp->variant_id == TP_VARIANT_IBM) { 307 /* 308 * Disable features that may make device unusable 309 * with this driver. 310 */ 311 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, 312 TP_MASK_TWOHAND, TP_DEF_TWOHAND); 313 314 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, 315 TP_MASK_SOURCE_TAG, TP_DEF_SOURCE_TAG); 316 317 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_MB, 318 TP_MASK_MB, TP_DEF_MB); 319 } 320 321 /* 322 * These properties can be changed in this driver. Only 323 * configure them if the values are non-default or if the TP is in 324 * an unknown state. 325 */ 326 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, sensitivity); 327 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, inertia); 328 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, speed); 329 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, reach); 330 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, draghys); 331 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, mindrag); 332 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, thresh); 333 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh); 334 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime); 335 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks); 336 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, drift_time); 337 338 /* toggles */ 339 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select); 340 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, skipback); 341 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ext_dev); 342 343 return 0; 344 } 345 346 static void trackpoint_defaults(struct trackpoint_data *tp) 347 { 348 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, sensitivity); 349 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, speed); 350 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, reach); 351 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, draghys); 352 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, mindrag); 353 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, thresh); 354 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh); 355 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime); 356 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks); 357 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, drift_time); 358 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia); 359 360 /* toggles */ 361 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, press_to_select); 362 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, skipback); 363 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ext_dev); 364 } 365 366 static void trackpoint_disconnect(struct psmouse *psmouse) 367 { 368 device_remove_group(&psmouse->ps2dev.serio->dev, 369 &trackpoint_attr_group); 370 371 kfree(psmouse->private); 372 psmouse->private = NULL; 373 } 374 375 static int trackpoint_reconnect(struct psmouse *psmouse) 376 { 377 struct trackpoint_data *tp = psmouse->private; 378 int error; 379 bool was_reset; 380 381 error = trackpoint_start_protocol(psmouse, NULL, NULL); 382 if (error) 383 return error; 384 385 was_reset = tp->variant_id == TP_VARIANT_IBM && 386 trackpoint_power_on_reset(&psmouse->ps2dev) == 0; 387 388 error = trackpoint_sync(psmouse, was_reset); 389 if (error) 390 return error; 391 392 return 0; 393 } 394 395 int trackpoint_detect(struct psmouse *psmouse, bool set_properties) 396 { 397 struct ps2dev *ps2dev = &psmouse->ps2dev; 398 struct trackpoint_data *tp; 399 u8 variant_id; 400 u8 firmware_id; 401 u8 button_info; 402 int error; 403 404 error = trackpoint_start_protocol(psmouse, &variant_id, &firmware_id); 405 if (error) 406 return error; 407 408 if (!set_properties) 409 return 0; 410 411 tp = kzalloc(sizeof(*tp), GFP_KERNEL); 412 if (!tp) 413 return -ENOMEM; 414 415 trackpoint_defaults(tp); 416 tp->variant_id = variant_id; 417 tp->firmware_id = firmware_id; 418 419 psmouse->private = tp; 420 421 psmouse->vendor = trackpoint_variants[variant_id]; 422 psmouse->name = "TrackPoint"; 423 424 psmouse->reconnect = trackpoint_reconnect; 425 psmouse->disconnect = trackpoint_disconnect; 426 427 if (variant_id != TP_VARIANT_IBM) { 428 /* Newer variants do not support extended button query. */ 429 button_info = 0x33; 430 } else { 431 error = trackpoint_read(ps2dev, TP_EXT_BTN, &button_info); 432 if (error) { 433 psmouse_warn(psmouse, 434 "failed to get extended button data, assuming 3 buttons\n"); 435 button_info = 0x33; 436 } else if (!button_info) { 437 psmouse_warn(psmouse, 438 "got 0 in extended button data, assuming 3 buttons\n"); 439 button_info = 0x33; 440 } 441 } 442 443 if ((button_info & 0x0f) >= 3) 444 input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE); 445 446 __set_bit(INPUT_PROP_POINTER, psmouse->dev->propbit); 447 __set_bit(INPUT_PROP_POINTING_STICK, psmouse->dev->propbit); 448 449 if (variant_id != TP_VARIANT_IBM || 450 trackpoint_power_on_reset(ps2dev) != 0) { 451 /* 452 * Write defaults to TP if we did not reset the trackpoint. 453 */ 454 trackpoint_sync(psmouse, false); 455 } 456 457 error = device_add_group(&ps2dev->serio->dev, &trackpoint_attr_group); 458 if (error) { 459 psmouse_err(psmouse, 460 "failed to create sysfs attributes, error: %d\n", 461 error); 462 kfree(psmouse->private); 463 psmouse->private = NULL; 464 return -1; 465 } 466 467 psmouse_info(psmouse, 468 "%s TrackPoint firmware: 0x%02x, buttons: %d/%d\n", 469 psmouse->vendor, firmware_id, 470 (button_info & 0xf0) >> 4, button_info & 0x0f); 471 472 return 0; 473 } 474 475