0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/slab.h>
0009 #include <linux/delay.h>
0010 #include <linux/serio.h>
0011 #include <linux/module.h>
0012 #include <linux/input.h>
0013 #include <linux/libps2.h>
0014 #include <linux/proc_fs.h>
0015 #include <linux/uaccess.h>
0016 #include "psmouse.h"
0017 #include "trackpoint.h"
0018
0019 static const char * const trackpoint_variants[] = {
0020 [TP_VARIANT_IBM] = "IBM",
0021 [TP_VARIANT_ALPS] = "ALPS",
0022 [TP_VARIANT_ELAN] = "Elan",
0023 [TP_VARIANT_NXP] = "NXP",
0024 [TP_VARIANT_JYT_SYNAPTICS] = "JYT_Synaptics",
0025 [TP_VARIANT_SYNAPTICS] = "Synaptics",
0026 };
0027
0028
0029
0030
0031
0032
0033 static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
0034 {
0035 u8 param[2] = { TP_POR };
0036 int err;
0037
0038 err = ps2_command(ps2dev, param, MAKE_PS2_CMD(1, 2, TP_COMMAND));
0039 if (err)
0040 return err;
0041
0042
0043 if (param[0] != 0xAA || param[1] != 0x00)
0044 return -ENODEV;
0045
0046 return 0;
0047 }
0048
0049
0050
0051
0052 static int trackpoint_read(struct ps2dev *ps2dev, u8 loc, u8 *results)
0053 {
0054 results[0] = loc;
0055
0056 return ps2_command(ps2dev, results, MAKE_PS2_CMD(1, 1, TP_COMMAND));
0057 }
0058
0059 static int trackpoint_write(struct ps2dev *ps2dev, u8 loc, u8 val)
0060 {
0061 u8 param[3] = { TP_WRITE_MEM, loc, val };
0062
0063 return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
0064 }
0065
0066 static int trackpoint_toggle_bit(struct ps2dev *ps2dev, u8 loc, u8 mask)
0067 {
0068 u8 param[3] = { TP_TOGGLE, loc, mask };
0069
0070
0071 if (loc < 0x20 || loc >= 0x2F)
0072 return -EINVAL;
0073
0074 return ps2_command(ps2dev, param, MAKE_PS2_CMD(3, 0, TP_COMMAND));
0075 }
0076
0077 static int trackpoint_update_bit(struct ps2dev *ps2dev,
0078 u8 loc, u8 mask, u8 value)
0079 {
0080 int retval;
0081 u8 data;
0082
0083 retval = trackpoint_read(ps2dev, loc, &data);
0084 if (retval)
0085 return retval;
0086
0087 if (((data & mask) == mask) != !!value)
0088 retval = trackpoint_toggle_bit(ps2dev, loc, mask);
0089
0090 return retval;
0091 }
0092
0093
0094
0095
0096 struct trackpoint_attr_data {
0097 size_t field_offset;
0098 u8 command;
0099 u8 mask;
0100 bool inverted;
0101 u8 power_on_default;
0102 };
0103
0104 static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse,
0105 void *data, char *buf)
0106 {
0107 struct trackpoint_data *tp = psmouse->private;
0108 struct trackpoint_attr_data *attr = data;
0109 u8 value = *(u8 *)((void *)tp + attr->field_offset);
0110
0111 if (attr->inverted)
0112 value = !value;
0113
0114 return sprintf(buf, "%u\n", value);
0115 }
0116
0117 static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
0118 const char *buf, size_t count)
0119 {
0120 struct trackpoint_data *tp = psmouse->private;
0121 struct trackpoint_attr_data *attr = data;
0122 u8 *field = (void *)tp + attr->field_offset;
0123 u8 value;
0124 int err;
0125
0126 err = kstrtou8(buf, 10, &value);
0127 if (err)
0128 return err;
0129
0130 *field = value;
0131 err = trackpoint_write(&psmouse->ps2dev, attr->command, value);
0132
0133 return err ?: count;
0134 }
0135
0136 #define TRACKPOINT_INT_ATTR(_name, _command, _default) \
0137 static struct trackpoint_attr_data trackpoint_attr_##_name = { \
0138 .field_offset = offsetof(struct trackpoint_data, _name), \
0139 .command = _command, \
0140 .power_on_default = _default, \
0141 }; \
0142 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
0143 &trackpoint_attr_##_name, \
0144 trackpoint_show_int_attr, trackpoint_set_int_attr)
0145
0146 static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
0147 const char *buf, size_t count)
0148 {
0149 struct trackpoint_data *tp = psmouse->private;
0150 struct trackpoint_attr_data *attr = data;
0151 bool *field = (void *)tp + attr->field_offset;
0152 bool value;
0153 int err;
0154
0155 err = kstrtobool(buf, &value);
0156 if (err)
0157 return err;
0158
0159 if (attr->inverted)
0160 value = !value;
0161
0162 if (*field != value) {
0163 *field = value;
0164 err = trackpoint_toggle_bit(&psmouse->ps2dev,
0165 attr->command, attr->mask);
0166 }
0167
0168 return err ?: count;
0169 }
0170
0171
0172 #define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv, _default) \
0173 static struct trackpoint_attr_data trackpoint_attr_##_name = { \
0174 .field_offset = offsetof(struct trackpoint_data, \
0175 _name), \
0176 .command = _command, \
0177 .mask = _mask, \
0178 .inverted = _inv, \
0179 .power_on_default = _default, \
0180 }; \
0181 PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
0182 &trackpoint_attr_##_name, \
0183 trackpoint_show_int_attr, trackpoint_set_bit_attr)
0184
0185 TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS);
0186 TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED);
0187 TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA);
0188 TRACKPOINT_INT_ATTR(reach, TP_REACH, TP_DEF_REACH);
0189 TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS, TP_DEF_DRAGHYS);
0190 TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG, TP_DEF_MINDRAG);
0191 TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH);
0192 TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH);
0193 TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME);
0194 TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV);
0195 TRACKPOINT_INT_ATTR(drift_time, TP_DRIFT_TIME, TP_DEF_DRIFT_TIME);
0196
0197 TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, false,
0198 TP_DEF_PTSON);
0199 TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, false,
0200 TP_DEF_SKIPBACK);
0201 TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, true,
0202 TP_DEF_EXT_DEV);
0203
0204 static bool trackpoint_is_attr_available(struct psmouse *psmouse,
0205 struct attribute *attr)
0206 {
0207 struct trackpoint_data *tp = psmouse->private;
0208
0209 return tp->variant_id == TP_VARIANT_IBM ||
0210 attr == &psmouse_attr_sensitivity.dattr.attr ||
0211 attr == &psmouse_attr_press_to_select.dattr.attr;
0212 }
0213
0214 static umode_t trackpoint_is_attr_visible(struct kobject *kobj,
0215 struct attribute *attr, int n)
0216 {
0217 struct device *dev = kobj_to_dev(kobj);
0218 struct serio *serio = to_serio_port(dev);
0219 struct psmouse *psmouse = serio_get_drvdata(serio);
0220
0221 return trackpoint_is_attr_available(psmouse, attr) ? attr->mode : 0;
0222 }
0223
0224 static struct attribute *trackpoint_attrs[] = {
0225 &psmouse_attr_sensitivity.dattr.attr,
0226 &psmouse_attr_speed.dattr.attr,
0227 &psmouse_attr_inertia.dattr.attr,
0228 &psmouse_attr_reach.dattr.attr,
0229 &psmouse_attr_draghys.dattr.attr,
0230 &psmouse_attr_mindrag.dattr.attr,
0231 &psmouse_attr_thresh.dattr.attr,
0232 &psmouse_attr_upthresh.dattr.attr,
0233 &psmouse_attr_ztime.dattr.attr,
0234 &psmouse_attr_jenks.dattr.attr,
0235 &psmouse_attr_drift_time.dattr.attr,
0236 &psmouse_attr_press_to_select.dattr.attr,
0237 &psmouse_attr_skipback.dattr.attr,
0238 &psmouse_attr_ext_dev.dattr.attr,
0239 NULL
0240 };
0241
0242 static struct attribute_group trackpoint_attr_group = {
0243 .is_visible = trackpoint_is_attr_visible,
0244 .attrs = trackpoint_attrs,
0245 };
0246
0247 #define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \
0248 do { \
0249 struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \
0250 \
0251 if ((!_power_on || _tp->_name != _attr->power_on_default) && \
0252 trackpoint_is_attr_available(_psmouse, \
0253 &psmouse_attr_##_name.dattr.attr)) { \
0254 if (!_attr->mask) \
0255 trackpoint_write(&_psmouse->ps2dev, \
0256 _attr->command, _tp->_name); \
0257 else \
0258 trackpoint_update_bit(&_psmouse->ps2dev, \
0259 _attr->command, _attr->mask, \
0260 _tp->_name); \
0261 } \
0262 } while (0)
0263
0264 #define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \
0265 do { \
0266 _tp->_name = trackpoint_attr_##_name.power_on_default; \
0267 } while (0)
0268
0269 static int trackpoint_start_protocol(struct psmouse *psmouse,
0270 u8 *variant_id, u8 *firmware_id)
0271 {
0272 u8 param[2] = { 0 };
0273 int error;
0274
0275 error = ps2_command(&psmouse->ps2dev,
0276 param, MAKE_PS2_CMD(0, 2, TP_READ_ID));
0277 if (error)
0278 return error;
0279
0280 switch (param[0]) {
0281 case TP_VARIANT_IBM:
0282 case TP_VARIANT_ALPS:
0283 case TP_VARIANT_ELAN:
0284 case TP_VARIANT_NXP:
0285 case TP_VARIANT_JYT_SYNAPTICS:
0286 case TP_VARIANT_SYNAPTICS:
0287 if (variant_id)
0288 *variant_id = param[0];
0289 if (firmware_id)
0290 *firmware_id = param[1];
0291 return 0;
0292 }
0293
0294 return -ENODEV;
0295 }
0296
0297
0298
0299
0300
0301
0302
0303 static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state)
0304 {
0305 struct trackpoint_data *tp = psmouse->private;
0306
0307 if (!in_power_on_state && tp->variant_id == TP_VARIANT_IBM) {
0308
0309
0310
0311
0312 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND,
0313 TP_MASK_TWOHAND, TP_DEF_TWOHAND);
0314
0315 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG,
0316 TP_MASK_SOURCE_TAG, TP_DEF_SOURCE_TAG);
0317
0318 trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_MB,
0319 TP_MASK_MB, TP_DEF_MB);
0320 }
0321
0322
0323
0324
0325
0326
0327 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, sensitivity);
0328 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, inertia);
0329 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, speed);
0330 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, reach);
0331 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, draghys);
0332 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, mindrag);
0333 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, thresh);
0334 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh);
0335 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime);
0336 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks);
0337 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, drift_time);
0338
0339
0340 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select);
0341 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, skipback);
0342 TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ext_dev);
0343
0344 return 0;
0345 }
0346
0347 static void trackpoint_defaults(struct trackpoint_data *tp)
0348 {
0349 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, sensitivity);
0350 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, speed);
0351 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, reach);
0352 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, draghys);
0353 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, mindrag);
0354 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, thresh);
0355 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh);
0356 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime);
0357 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks);
0358 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, drift_time);
0359 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia);
0360
0361
0362 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, press_to_select);
0363 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, skipback);
0364 TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ext_dev);
0365 }
0366
0367 static void trackpoint_disconnect(struct psmouse *psmouse)
0368 {
0369 device_remove_group(&psmouse->ps2dev.serio->dev,
0370 &trackpoint_attr_group);
0371
0372 kfree(psmouse->private);
0373 psmouse->private = NULL;
0374 }
0375
0376 static int trackpoint_reconnect(struct psmouse *psmouse)
0377 {
0378 struct trackpoint_data *tp = psmouse->private;
0379 int error;
0380 bool was_reset;
0381
0382 error = trackpoint_start_protocol(psmouse, NULL, NULL);
0383 if (error)
0384 return error;
0385
0386 was_reset = tp->variant_id == TP_VARIANT_IBM &&
0387 trackpoint_power_on_reset(&psmouse->ps2dev) == 0;
0388
0389 error = trackpoint_sync(psmouse, was_reset);
0390 if (error)
0391 return error;
0392
0393 return 0;
0394 }
0395
0396 int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
0397 {
0398 struct ps2dev *ps2dev = &psmouse->ps2dev;
0399 struct trackpoint_data *tp;
0400 u8 variant_id;
0401 u8 firmware_id;
0402 u8 button_info;
0403 int error;
0404
0405 error = trackpoint_start_protocol(psmouse, &variant_id, &firmware_id);
0406 if (error)
0407 return error;
0408
0409 if (!set_properties)
0410 return 0;
0411
0412 tp = kzalloc(sizeof(*tp), GFP_KERNEL);
0413 if (!tp)
0414 return -ENOMEM;
0415
0416 trackpoint_defaults(tp);
0417 tp->variant_id = variant_id;
0418 tp->firmware_id = firmware_id;
0419
0420 psmouse->private = tp;
0421
0422 psmouse->vendor = trackpoint_variants[variant_id];
0423 psmouse->name = "TrackPoint";
0424
0425 psmouse->reconnect = trackpoint_reconnect;
0426 psmouse->disconnect = trackpoint_disconnect;
0427
0428 if (variant_id != TP_VARIANT_IBM) {
0429
0430 button_info = 0x33;
0431 } else {
0432 error = trackpoint_read(ps2dev, TP_EXT_BTN, &button_info);
0433 if (error) {
0434 psmouse_warn(psmouse,
0435 "failed to get extended button data, assuming 3 buttons\n");
0436 button_info = 0x33;
0437 } else if (!button_info) {
0438 psmouse_warn(psmouse,
0439 "got 0 in extended button data, assuming 3 buttons\n");
0440 button_info = 0x33;
0441 }
0442 }
0443
0444 if ((button_info & 0x0f) >= 3)
0445 input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
0446
0447 __set_bit(INPUT_PROP_POINTER, psmouse->dev->propbit);
0448 __set_bit(INPUT_PROP_POINTING_STICK, psmouse->dev->propbit);
0449
0450 if (variant_id != TP_VARIANT_IBM ||
0451 trackpoint_power_on_reset(ps2dev) != 0) {
0452
0453
0454
0455 trackpoint_sync(psmouse, false);
0456 }
0457
0458 error = device_add_group(&ps2dev->serio->dev, &trackpoint_attr_group);
0459 if (error) {
0460 psmouse_err(psmouse,
0461 "failed to create sysfs attributes, error: %d\n",
0462 error);
0463 kfree(psmouse->private);
0464 psmouse->private = NULL;
0465 return -1;
0466 }
0467
0468 psmouse_info(psmouse,
0469 "%s TrackPoint firmware: 0x%02x, buttons: %d/%d\n",
0470 psmouse->vendor, firmware_id,
0471 (button_info & 0xf0) >> 4, button_info & 0x0f);
0472
0473 return 0;
0474 }
0475