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