Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: psmouse - add support for IBM TrackPoint devices.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Stephen Evanchik and committed by
Dmitry Torokhov
541e316a 6fc32179

+460 -2
+1 -1
drivers/input/mouse/Makefile
··· 15 15 obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o 16 16 obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o 17 17 18 - psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o 18 + psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o
+14 -1
drivers/input/mouse/psmouse-base.c
··· 25 25 #include "logips2pp.h" 26 26 #include "alps.h" 27 27 #include "lifebook.h" 28 + #include "trackpoint.h" 28 29 29 30 #define DRIVER_DESC "PS/2 mouse driver" 30 31 ··· 521 520 return PSMOUSE_IMPS; 522 521 523 522 /* 523 + * Try to initialize the IBM TrackPoint 524 + */ 525 + if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0) 526 + return PSMOUSE_TRACKPOINT; 527 + 528 + /* 524 529 * Okay, all failed, we have a standard mouse here. The number of the buttons 525 530 * is still a question, though. We assume 3. 526 531 */ ··· 605 598 .name = "LBPS/2", 606 599 .alias = "lifebook", 607 600 .init = lifebook_init, 601 + }, 602 + { 603 + .type = PSMOUSE_TRACKPOINT, 604 + .name = "TPPS/2", 605 + .alias = "trackpoint", 606 + .detect = trackpoint_detect, 608 607 }, 609 608 { 610 609 .type = PSMOUSE_AUTO, ··· 1247 1234 1248 1235 *((unsigned int *)kp->arg) = proto->type; 1249 1236 1250 - return 0; \ 1237 + return 0; 1251 1238 } 1252 1239 1253 1240 static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
+1
drivers/input/mouse/psmouse.h
··· 78 78 PSMOUSE_SYNAPTICS, 79 79 PSMOUSE_ALPS, 80 80 PSMOUSE_LIFEBOOK, 81 + PSMOUSE_TRACKPOINT, 81 82 PSMOUSE_AUTO /* This one should always be last */ 82 83 }; 83 84
+297
drivers/input/mouse/trackpoint.c
··· 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/delay.h> 12 + #include <linux/serio.h> 13 + #include <linux/module.h> 14 + #include <linux/moduleparam.h> 15 + #include <linux/input.h> 16 + #include <linux/libps2.h> 17 + #include <linux/proc_fs.h> 18 + #include <asm/uaccess.h> 19 + #include "psmouse.h" 20 + #include "trackpoint.h" 21 + 22 + PSMOUSE_DEFINE_ATTR(sensitivity); 23 + PSMOUSE_DEFINE_ATTR(speed); 24 + PSMOUSE_DEFINE_ATTR(inertia); 25 + PSMOUSE_DEFINE_ATTR(reach); 26 + PSMOUSE_DEFINE_ATTR(draghys); 27 + PSMOUSE_DEFINE_ATTR(mindrag); 28 + PSMOUSE_DEFINE_ATTR(thresh); 29 + PSMOUSE_DEFINE_ATTR(upthresh); 30 + PSMOUSE_DEFINE_ATTR(ztime); 31 + PSMOUSE_DEFINE_ATTR(jenks); 32 + PSMOUSE_DEFINE_ATTR(press_to_select); 33 + PSMOUSE_DEFINE_ATTR(skipback); 34 + PSMOUSE_DEFINE_ATTR(ext_dev); 35 + 36 + #define MAKE_ATTR_READ(_item) \ 37 + static ssize_t psmouse_attr_show_##_item(struct psmouse *psmouse, char *buf) \ 38 + { \ 39 + struct trackpoint_data *tp = psmouse->private; \ 40 + return sprintf(buf, "%lu\n", (unsigned long)tp->_item); \ 41 + } 42 + 43 + #define MAKE_ATTR_WRITE(_item, command) \ 44 + static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \ 45 + { \ 46 + char *rest; \ 47 + unsigned long value; \ 48 + struct trackpoint_data *tp = psmouse->private; \ 49 + value = simple_strtoul(buf, &rest, 10); \ 50 + if (*rest) \ 51 + return -EINVAL; \ 52 + tp->_item = value; \ 53 + trackpoint_write(&psmouse->ps2dev, command, tp->_item); \ 54 + return count; \ 55 + } 56 + 57 + #define MAKE_ATTR_TOGGLE(_item, command, mask) \ 58 + static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \ 59 + { \ 60 + unsigned char toggle; \ 61 + struct trackpoint_data *tp = psmouse->private; \ 62 + toggle = (buf[0] == '1') ? 1 : 0; \ 63 + if (toggle != tp->_item) { \ 64 + tp->_item = toggle; \ 65 + trackpoint_toggle_bit(&psmouse->ps2dev, command, mask); \ 66 + } \ 67 + return count; \ 68 + } 69 + 70 + /* 71 + * Device IO: read, write and toggle bit 72 + */ 73 + static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results) 74 + { 75 + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 76 + ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { 77 + return -1; 78 + } 79 + 80 + return 0; 81 + } 82 + 83 + static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val) 84 + { 85 + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 86 + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || 87 + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || 88 + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) { 89 + return -1; 90 + } 91 + 92 + return 0; 93 + } 94 + 95 + static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask) 96 + { 97 + /* Bad things will happen if the loc param isn't in this range */ 98 + if (loc < 0x20 || loc >= 0x2F) 99 + return -1; 100 + 101 + if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || 102 + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) || 103 + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || 104 + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) { 105 + return -1; 106 + } 107 + 108 + return 0; 109 + } 110 + 111 + MAKE_ATTR_WRITE(sensitivity, TP_SENS); 112 + MAKE_ATTR_READ(sensitivity); 113 + 114 + MAKE_ATTR_WRITE(speed, TP_SPEED); 115 + MAKE_ATTR_READ(speed); 116 + 117 + MAKE_ATTR_WRITE(inertia, TP_INERTIA); 118 + MAKE_ATTR_READ(inertia); 119 + 120 + MAKE_ATTR_WRITE(reach, TP_REACH); 121 + MAKE_ATTR_READ(reach); 122 + 123 + MAKE_ATTR_WRITE(draghys, TP_DRAGHYS); 124 + MAKE_ATTR_READ(draghys); 125 + 126 + MAKE_ATTR_WRITE(mindrag, TP_MINDRAG); 127 + MAKE_ATTR_READ(mindrag); 128 + 129 + MAKE_ATTR_WRITE(thresh, TP_THRESH); 130 + MAKE_ATTR_READ(thresh); 131 + 132 + MAKE_ATTR_WRITE(upthresh, TP_UP_THRESH); 133 + MAKE_ATTR_READ(upthresh); 134 + 135 + MAKE_ATTR_WRITE(ztime, TP_Z_TIME); 136 + MAKE_ATTR_READ(ztime); 137 + 138 + MAKE_ATTR_WRITE(jenks, TP_JENKS_CURV); 139 + MAKE_ATTR_READ(jenks); 140 + 141 + MAKE_ATTR_TOGGLE(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON); 142 + MAKE_ATTR_READ(press_to_select); 143 + 144 + MAKE_ATTR_TOGGLE(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); 145 + MAKE_ATTR_READ(skipback); 146 + 147 + MAKE_ATTR_TOGGLE(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); 148 + MAKE_ATTR_READ(ext_dev); 149 + 150 + static struct attribute *trackpoint_attrs[] = { 151 + &psmouse_attr_sensitivity.attr, 152 + &psmouse_attr_speed.attr, 153 + &psmouse_attr_inertia.attr, 154 + &psmouse_attr_reach.attr, 155 + &psmouse_attr_draghys.attr, 156 + &psmouse_attr_mindrag.attr, 157 + &psmouse_attr_thresh.attr, 158 + &psmouse_attr_upthresh.attr, 159 + &psmouse_attr_ztime.attr, 160 + &psmouse_attr_jenks.attr, 161 + &psmouse_attr_press_to_select.attr, 162 + &psmouse_attr_skipback.attr, 163 + &psmouse_attr_ext_dev.attr, 164 + NULL 165 + }; 166 + 167 + static struct attribute_group trackpoint_attr_group = { 168 + .attrs = trackpoint_attrs, 169 + }; 170 + 171 + static void trackpoint_disconnect(struct psmouse *psmouse) 172 + { 173 + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); 174 + 175 + kfree(psmouse->private); 176 + psmouse->private = NULL; 177 + } 178 + 179 + static int trackpoint_sync(struct psmouse *psmouse) 180 + { 181 + unsigned char toggle; 182 + struct trackpoint_data *tp = psmouse->private; 183 + 184 + if (!tp) 185 + return -1; 186 + 187 + /* Disable features that may make device unusable with this driver */ 188 + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle); 189 + if (toggle & TP_MASK_TWOHAND) 190 + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND); 191 + 192 + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle); 193 + if (toggle & TP_MASK_SOURCE_TAG) 194 + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG); 195 + 196 + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle); 197 + if (toggle & TP_MASK_MB) 198 + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB); 199 + 200 + /* Push the config to the device */ 201 + trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity); 202 + trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia); 203 + trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed); 204 + 205 + trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach); 206 + trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys); 207 + trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag); 208 + 209 + trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh); 210 + trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh); 211 + 212 + trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime); 213 + trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks); 214 + 215 + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle); 216 + if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select) 217 + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON); 218 + 219 + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle); 220 + if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback) 221 + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); 222 + 223 + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle); 224 + if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev) 225 + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); 226 + 227 + return 0; 228 + } 229 + 230 + static void trackpoint_defaults(struct trackpoint_data *tp) 231 + { 232 + tp->press_to_select = TP_DEF_PTSON; 233 + tp->sensitivity = TP_DEF_SENS; 234 + tp->speed = TP_DEF_SPEED; 235 + tp->reach = TP_DEF_REACH; 236 + 237 + tp->draghys = TP_DEF_DRAGHYS; 238 + tp->mindrag = TP_DEF_MINDRAG; 239 + 240 + tp->thresh = TP_DEF_THRESH; 241 + tp->upthresh = TP_DEF_UP_THRESH; 242 + 243 + tp->ztime = TP_DEF_Z_TIME; 244 + tp->jenks = TP_DEF_JENKS_CURV; 245 + 246 + tp->inertia = TP_DEF_INERTIA; 247 + tp->skipback = TP_DEF_SKIPBACK; 248 + tp->ext_dev = TP_DEF_EXT_DEV; 249 + } 250 + 251 + int trackpoint_detect(struct psmouse *psmouse, int set_properties) 252 + { 253 + struct trackpoint_data *priv; 254 + struct ps2dev *ps2dev = &psmouse->ps2dev; 255 + unsigned char firmware_id; 256 + unsigned char button_info; 257 + unsigned char param[2]; 258 + 259 + param[0] = param[1] = 0; 260 + 261 + if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID))) 262 + return -1; 263 + 264 + if (param[0] != TP_MAGIC_IDENT) 265 + return -1; 266 + 267 + if (!set_properties) 268 + return 0; 269 + 270 + firmware_id = param[1]; 271 + 272 + if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { 273 + printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n"); 274 + button_info = 0; 275 + } 276 + 277 + psmouse->private = priv = kcalloc(1, sizeof(struct trackpoint_data), GFP_KERNEL); 278 + if (!priv) 279 + return -1; 280 + 281 + psmouse->vendor = "IBM"; 282 + psmouse->name = "TrackPoint"; 283 + 284 + psmouse->reconnect = trackpoint_sync; 285 + psmouse->disconnect = trackpoint_disconnect; 286 + 287 + trackpoint_defaults(priv); 288 + trackpoint_sync(psmouse); 289 + 290 + sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); 291 + 292 + printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n", 293 + firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f); 294 + 295 + return 0; 296 + } 297 +
+147
drivers/input/mouse/trackpoint.h
··· 1 + /* 2 + * IBM TrackPoint PS/2 mouse driver 3 + * 4 + * Stephen Evanchik <evanchsa@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License version 2 as published by 8 + * the Free Software Foundation. 9 + */ 10 + 11 + #ifndef _TRACKPOINT_H 12 + #define _TRACKPOINT_H 13 + 14 + /* 15 + * These constants are from the TrackPoint System 16 + * Engineering documentation Version 4 from IBM Watson 17 + * research: 18 + * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html 19 + */ 20 + 21 + #define TP_COMMAND 0xE2 /* Commands start with this */ 22 + 23 + #define TP_READ_ID 0xE1 /* Sent for device identification */ 24 + #define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */ 25 + /* by the firmware ID */ 26 + 27 + 28 + /* 29 + * Commands 30 + */ 31 + #define TP_RECALIB 0x51 /* Recalibrate */ 32 + #define TP_POWER_DOWN 0x44 /* Can only be undone through HW reset */ 33 + #define TP_EXT_DEV 0x21 /* Determines if external device is connected (RO) */ 34 + #define TP_EXT_BTN 0x4B /* Read extended button status */ 35 + #define TP_POR 0x7F /* Execute Power on Reset */ 36 + #define TP_POR_RESULTS 0x25 /* Read Power on Self test results */ 37 + #define TP_DISABLE_EXT 0x40 /* Disable external pointing device */ 38 + #define TP_ENABLE_EXT 0x41 /* Enable external pointing device */ 39 + 40 + /* 41 + * Mode manipulation 42 + */ 43 + #define TP_SET_SOFT_TRANS 0x4E /* Set mode */ 44 + #define TP_CANCEL_SOFT_TRANS 0xB9 /* Cancel mode */ 45 + #define TP_SET_HARD_TRANS 0x45 /* Mode can only be set */ 46 + 47 + 48 + /* 49 + * Register oriented commands/properties 50 + */ 51 + #define TP_WRITE_MEM 0x81 52 + #define TP_READ_MEM 0x80 /* Not used in this implementation */ 53 + 54 + /* 55 + * RAM Locations for properties 56 + */ 57 + #define TP_SENS 0x4A /* Sensitivity */ 58 + #define TP_MB 0x4C /* Read Middle Button Status (RO) */ 59 + #define TP_INERTIA 0x4D /* Negative Inertia */ 60 + #define TP_SPEED 0x60 /* Speed of TP Cursor */ 61 + #define TP_REACH 0x57 /* Backup for Z-axis press */ 62 + #define TP_DRAGHYS 0x58 /* Drag Hysteresis */ 63 + /* (how hard it is to drag */ 64 + /* with Z-axis pressed) */ 65 + 66 + #define TP_MINDRAG 0x59 /* Minimum amount of force needed */ 67 + /* to trigger dragging */ 68 + 69 + #define TP_THRESH 0x5C /* Minimum value for a Z-axis press */ 70 + #define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */ 71 + #define TP_Z_TIME 0x5E /* How sharp of a press */ 72 + #define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */ 73 + 74 + /* 75 + * Toggling Flag bits 76 + */ 77 + #define TP_TOGGLE 0x47 /* Toggle command */ 78 + 79 + #define TP_TOGGLE_MB 0x23 /* Disable/Enable Middle Button */ 80 + #define TP_MASK_MB 0x01 81 + #define TP_TOGGLE_EXT_DEV 0x23 /* Toggle external device */ 82 + #define TP_MASK_EXT_DEV 0x02 83 + #define TP_TOGGLE_DRIFT 0x23 /* Drift Correction */ 84 + #define TP_MASK_DRIFT 0x80 85 + #define TP_TOGGLE_BURST 0x28 /* Burst Mode */ 86 + #define TP_MASK_BURST 0x80 87 + #define TP_TOGGLE_PTSON 0x2C /* Press to Select */ 88 + #define TP_MASK_PTSON 0x01 89 + #define TP_TOGGLE_HARD_TRANS 0x2C /* Alternate method to set Hard Transparency */ 90 + #define TP_MASK_HARD_TRANS 0x80 91 + #define TP_TOGGLE_TWOHAND 0x2D /* Two handed */ 92 + #define TP_MASK_TWOHAND 0x01 93 + #define TP_TOGGLE_STICKY_TWO 0x2D /* Sticky two handed */ 94 + #define TP_MASK_STICKY_TWO 0x04 95 + #define TP_TOGGLE_SKIPBACK 0x2D /* Suppress movement after drag release */ 96 + #define TP_MASK_SKIPBACK 0x08 97 + #define TP_TOGGLE_SOURCE_TAG 0x20 /* Bit 3 of the first packet will be set to 98 + to the origin of the packet (external or TP) */ 99 + #define TP_MASK_SOURCE_TAG 0x80 100 + #define TP_TOGGLE_EXT_TAG 0x22 /* Bit 3 of the first packet coming from the 101 + external device will be forced to 1 */ 102 + #define TP_MASK_EXT_TAG 0x04 103 + 104 + 105 + /* Power on Self Test Results */ 106 + #define TP_POR_SUCCESS 0x3B 107 + 108 + /* 109 + * Default power on values 110 + */ 111 + #define TP_DEF_SENS 0x80 112 + #define TP_DEF_INERTIA 0x06 113 + #define TP_DEF_SPEED 0x61 114 + #define TP_DEF_REACH 0x0A 115 + 116 + #define TP_DEF_DRAGHYS 0xFF 117 + #define TP_DEF_MINDRAG 0x14 118 + 119 + #define TP_DEF_THRESH 0x08 120 + #define TP_DEF_UP_THRESH 0xFF 121 + #define TP_DEF_Z_TIME 0x26 122 + #define TP_DEF_JENKS_CURV 0x87 123 + 124 + /* Toggles */ 125 + #define TP_DEF_MB 0x00 126 + #define TP_DEF_PTSON 0x00 127 + #define TP_DEF_SKIPBACK 0x00 128 + #define TP_DEF_EXT_DEV 0x01 129 + 130 + #define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) 131 + 132 + struct trackpoint_data 133 + { 134 + unsigned char sensitivity, speed, inertia, reach; 135 + unsigned char draghys, mindrag; 136 + unsigned char thresh, upthresh; 137 + unsigned char ztime, jenks; 138 + 139 + unsigned char press_to_select; 140 + unsigned char skipback; 141 + 142 + unsigned char ext_dev; 143 + }; 144 + 145 + extern int trackpoint_detect(struct psmouse *psmouse, int set_properties); 146 + 147 + #endif /* _TRACKPOINT_H */