Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Stephen Evanchik <evanchsa@gmail.com>
0004  *
0005  * Trademarks are the property of their respective owners.
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  * Power-on Reset: Resets all trackpoint parameters, including RAM values,
0030  * to defaults.
0031  * Returns zero on success, non-zero on failure.
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     /* Check for success response -- 0xAA00 */
0043     if (param[0] != 0xAA || param[1] != 0x00)
0044         return -ENODEV;
0045 
0046     return 0;
0047 }
0048 
0049 /*
0050  * Device IO: read, write and toggle bit
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     /* Bad things will happen if the loc param isn't in this range */
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  * Trackpoint-specific attributes
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  * Write parameters to trackpad.
0299  * in_power_on_state: Set to true if TP is in default / power-on state (ex. if
0300  *            power-on reset was run). If so, values will only be
0301  *            written to TP if they differ from power-on default.
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          * Disable features that may make device unusable
0310          * with this driver.
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      * These properties can be changed in this driver. Only
0324      * configure them if the values are non-default or if the TP is in
0325      * an unknown state.
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     /* toggles */
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     /* toggles */
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         /* Newer variants do not support extended button query. */
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          * Write defaults to TP if we did not reset the trackpoint.
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