···2525#include "logips2pp.h"2626#include "alps.h"2727#include "lifebook.h"2828+#include "trackpoint.h"28292930#define DRIVER_DESC "PS/2 mouse driver"3031···521520 return PSMOUSE_IMPS;522521523522/*523523+ * Try to initialize the IBM TrackPoint524524+ */525525+ if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)526526+ return PSMOUSE_TRACKPOINT;527527+528528+/*524529 * Okay, all failed, we have a standard mouse here. The number of the buttons525530 * is still a question, though. We assume 3.526531 */···605598 .name = "LBPS/2",606599 .alias = "lifebook",607600 .init = lifebook_init,601601+ },602602+ {603603+ .type = PSMOUSE_TRACKPOINT,604604+ .name = "TPPS/2",605605+ .alias = "trackpoint",606606+ .detect = trackpoint_detect,608607 },609608 {610609 .type = PSMOUSE_AUTO,···1247123412481235 *((unsigned int *)kp->arg) = proto->type;1249123612501250- return 0; \12371237+ return 0;12511238}1252123912531240static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
+1
drivers/input/mouse/psmouse.h
···7878 PSMOUSE_SYNAPTICS,7979 PSMOUSE_ALPS,8080 PSMOUSE_LIFEBOOK,8181+ PSMOUSE_TRACKPOINT,8182 PSMOUSE_AUTO /* This one should always be last */8283};8384
+297
drivers/input/mouse/trackpoint.c
···11+/*22+ * Stephen Evanchik <evanchsa@gmail.com>33+ *44+ * This program is free software; you can redistribute it and/or modify it55+ * under the terms of the GNU General Public License version 2 as published by66+ * the Free Software Foundation.77+ *88+ * Trademarks are the property of their respective owners.99+ */1010+1111+#include <linux/delay.h>1212+#include <linux/serio.h>1313+#include <linux/module.h>1414+#include <linux/moduleparam.h>1515+#include <linux/input.h>1616+#include <linux/libps2.h>1717+#include <linux/proc_fs.h>1818+#include <asm/uaccess.h>1919+#include "psmouse.h"2020+#include "trackpoint.h"2121+2222+PSMOUSE_DEFINE_ATTR(sensitivity);2323+PSMOUSE_DEFINE_ATTR(speed);2424+PSMOUSE_DEFINE_ATTR(inertia);2525+PSMOUSE_DEFINE_ATTR(reach);2626+PSMOUSE_DEFINE_ATTR(draghys);2727+PSMOUSE_DEFINE_ATTR(mindrag);2828+PSMOUSE_DEFINE_ATTR(thresh);2929+PSMOUSE_DEFINE_ATTR(upthresh);3030+PSMOUSE_DEFINE_ATTR(ztime);3131+PSMOUSE_DEFINE_ATTR(jenks);3232+PSMOUSE_DEFINE_ATTR(press_to_select);3333+PSMOUSE_DEFINE_ATTR(skipback);3434+PSMOUSE_DEFINE_ATTR(ext_dev);3535+3636+#define MAKE_ATTR_READ(_item) \3737+ static ssize_t psmouse_attr_show_##_item(struct psmouse *psmouse, char *buf) \3838+ { \3939+ struct trackpoint_data *tp = psmouse->private; \4040+ return sprintf(buf, "%lu\n", (unsigned long)tp->_item); \4141+ }4242+4343+#define MAKE_ATTR_WRITE(_item, command) \4444+ static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \4545+ { \4646+ char *rest; \4747+ unsigned long value; \4848+ struct trackpoint_data *tp = psmouse->private; \4949+ value = simple_strtoul(buf, &rest, 10); \5050+ if (*rest) \5151+ return -EINVAL; \5252+ tp->_item = value; \5353+ trackpoint_write(&psmouse->ps2dev, command, tp->_item); \5454+ return count; \5555+ }5656+5757+#define MAKE_ATTR_TOGGLE(_item, command, mask) \5858+ static ssize_t psmouse_attr_set_##_item(struct psmouse *psmouse, const char *buf, size_t count) \5959+ { \6060+ unsigned char toggle; \6161+ struct trackpoint_data *tp = psmouse->private; \6262+ toggle = (buf[0] == '1') ? 1 : 0; \6363+ if (toggle != tp->_item) { \6464+ tp->_item = toggle; \6565+ trackpoint_toggle_bit(&psmouse->ps2dev, command, mask); \6666+ } \6767+ return count; \6868+ }6969+7070+/*7171+ * Device IO: read, write and toggle bit7272+ */7373+static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results)7474+{7575+ if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||7676+ ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {7777+ return -1;7878+ }7979+8080+ return 0;8181+}8282+8383+static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val)8484+{8585+ if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||8686+ ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||8787+ ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||8888+ ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) {8989+ return -1;9090+ }9191+9292+ return 0;9393+}9494+9595+static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask)9696+{9797+ /* Bad things will happen if the loc param isn't in this range */9898+ if (loc < 0x20 || loc >= 0x2F)9999+ return -1;100100+101101+ if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||102102+ ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) ||103103+ ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) ||104104+ ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) {105105+ return -1;106106+ }107107+108108+ return 0;109109+}110110+111111+MAKE_ATTR_WRITE(sensitivity, TP_SENS);112112+MAKE_ATTR_READ(sensitivity);113113+114114+MAKE_ATTR_WRITE(speed, TP_SPEED);115115+MAKE_ATTR_READ(speed);116116+117117+MAKE_ATTR_WRITE(inertia, TP_INERTIA);118118+MAKE_ATTR_READ(inertia);119119+120120+MAKE_ATTR_WRITE(reach, TP_REACH);121121+MAKE_ATTR_READ(reach);122122+123123+MAKE_ATTR_WRITE(draghys, TP_DRAGHYS);124124+MAKE_ATTR_READ(draghys);125125+126126+MAKE_ATTR_WRITE(mindrag, TP_MINDRAG);127127+MAKE_ATTR_READ(mindrag);128128+129129+MAKE_ATTR_WRITE(thresh, TP_THRESH);130130+MAKE_ATTR_READ(thresh);131131+132132+MAKE_ATTR_WRITE(upthresh, TP_UP_THRESH);133133+MAKE_ATTR_READ(upthresh);134134+135135+MAKE_ATTR_WRITE(ztime, TP_Z_TIME);136136+MAKE_ATTR_READ(ztime);137137+138138+MAKE_ATTR_WRITE(jenks, TP_JENKS_CURV);139139+MAKE_ATTR_READ(jenks);140140+141141+MAKE_ATTR_TOGGLE(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON);142142+MAKE_ATTR_READ(press_to_select);143143+144144+MAKE_ATTR_TOGGLE(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK);145145+MAKE_ATTR_READ(skipback);146146+147147+MAKE_ATTR_TOGGLE(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV);148148+MAKE_ATTR_READ(ext_dev);149149+150150+static struct attribute *trackpoint_attrs[] = {151151+ &psmouse_attr_sensitivity.attr,152152+ &psmouse_attr_speed.attr,153153+ &psmouse_attr_inertia.attr,154154+ &psmouse_attr_reach.attr,155155+ &psmouse_attr_draghys.attr,156156+ &psmouse_attr_mindrag.attr,157157+ &psmouse_attr_thresh.attr,158158+ &psmouse_attr_upthresh.attr,159159+ &psmouse_attr_ztime.attr,160160+ &psmouse_attr_jenks.attr,161161+ &psmouse_attr_press_to_select.attr,162162+ &psmouse_attr_skipback.attr,163163+ &psmouse_attr_ext_dev.attr,164164+ NULL165165+};166166+167167+static struct attribute_group trackpoint_attr_group = {168168+ .attrs = trackpoint_attrs,169169+};170170+171171+static void trackpoint_disconnect(struct psmouse *psmouse)172172+{173173+ sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group);174174+175175+ kfree(psmouse->private);176176+ psmouse->private = NULL;177177+}178178+179179+static int trackpoint_sync(struct psmouse *psmouse)180180+{181181+ unsigned char toggle;182182+ struct trackpoint_data *tp = psmouse->private;183183+184184+ if (!tp)185185+ return -1;186186+187187+ /* Disable features that may make device unusable with this driver */188188+ trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle);189189+ if (toggle & TP_MASK_TWOHAND)190190+ trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND);191191+192192+ trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle);193193+ if (toggle & TP_MASK_SOURCE_TAG)194194+ trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG);195195+196196+ trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle);197197+ if (toggle & TP_MASK_MB)198198+ trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB);199199+200200+ /* Push the config to the device */201201+ trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity);202202+ trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia);203203+ trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed);204204+205205+ trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach);206206+ trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys);207207+ trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag);208208+209209+ trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh);210210+ trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh);211211+212212+ trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime);213213+ trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks);214214+215215+ trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle);216216+ if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select)217217+ trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON);218218+219219+ trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle);220220+ if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback)221221+ trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK);222222+223223+ trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle);224224+ if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev)225225+ trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV);226226+227227+ return 0;228228+}229229+230230+static void trackpoint_defaults(struct trackpoint_data *tp)231231+{232232+ tp->press_to_select = TP_DEF_PTSON;233233+ tp->sensitivity = TP_DEF_SENS;234234+ tp->speed = TP_DEF_SPEED;235235+ tp->reach = TP_DEF_REACH;236236+237237+ tp->draghys = TP_DEF_DRAGHYS;238238+ tp->mindrag = TP_DEF_MINDRAG;239239+240240+ tp->thresh = TP_DEF_THRESH;241241+ tp->upthresh = TP_DEF_UP_THRESH;242242+243243+ tp->ztime = TP_DEF_Z_TIME;244244+ tp->jenks = TP_DEF_JENKS_CURV;245245+246246+ tp->inertia = TP_DEF_INERTIA;247247+ tp->skipback = TP_DEF_SKIPBACK;248248+ tp->ext_dev = TP_DEF_EXT_DEV;249249+}250250+251251+int trackpoint_detect(struct psmouse *psmouse, int set_properties)252252+{253253+ struct trackpoint_data *priv;254254+ struct ps2dev *ps2dev = &psmouse->ps2dev;255255+ unsigned char firmware_id;256256+ unsigned char button_info;257257+ unsigned char param[2];258258+259259+ param[0] = param[1] = 0;260260+261261+ if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))262262+ return -1;263263+264264+ if (param[0] != TP_MAGIC_IDENT)265265+ return -1;266266+267267+ if (!set_properties)268268+ return 0;269269+270270+ firmware_id = param[1];271271+272272+ if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {273273+ printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n");274274+ button_info = 0;275275+ }276276+277277+ psmouse->private = priv = kcalloc(1, sizeof(struct trackpoint_data), GFP_KERNEL);278278+ if (!priv)279279+ return -1;280280+281281+ psmouse->vendor = "IBM";282282+ psmouse->name = "TrackPoint";283283+284284+ psmouse->reconnect = trackpoint_sync;285285+ psmouse->disconnect = trackpoint_disconnect;286286+287287+ trackpoint_defaults(priv);288288+ trackpoint_sync(psmouse);289289+290290+ sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);291291+292292+ printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n",293293+ firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f);294294+295295+ return 0;296296+}297297+
+147
drivers/input/mouse/trackpoint.h
···11+/*22+ * IBM TrackPoint PS/2 mouse driver33+ *44+ * Stephen Evanchik <evanchsa@gmail.com>55+ *66+ * This program is free software; you can redistribute it and/or modify it77+ * under the terms of the GNU General Public License version 2 as published by88+ * the Free Software Foundation.99+ */1010+1111+#ifndef _TRACKPOINT_H1212+#define _TRACKPOINT_H1313+1414+/*1515+ * These constants are from the TrackPoint System1616+ * Engineering documentation Version 4 from IBM Watson1717+ * research:1818+ * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html1919+ */2020+2121+#define TP_COMMAND 0xE2 /* Commands start with this */2222+2323+#define TP_READ_ID 0xE1 /* Sent for device identification */2424+#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */2525+ /* by the firmware ID */2626+2727+2828+/*2929+ * Commands3030+ */3131+#define TP_RECALIB 0x51 /* Recalibrate */3232+#define TP_POWER_DOWN 0x44 /* Can only be undone through HW reset */3333+#define TP_EXT_DEV 0x21 /* Determines if external device is connected (RO) */3434+#define TP_EXT_BTN 0x4B /* Read extended button status */3535+#define TP_POR 0x7F /* Execute Power on Reset */3636+#define TP_POR_RESULTS 0x25 /* Read Power on Self test results */3737+#define TP_DISABLE_EXT 0x40 /* Disable external pointing device */3838+#define TP_ENABLE_EXT 0x41 /* Enable external pointing device */3939+4040+/*4141+ * Mode manipulation4242+ */4343+#define TP_SET_SOFT_TRANS 0x4E /* Set mode */4444+#define TP_CANCEL_SOFT_TRANS 0xB9 /* Cancel mode */4545+#define TP_SET_HARD_TRANS 0x45 /* Mode can only be set */4646+4747+4848+/*4949+ * Register oriented commands/properties5050+ */5151+#define TP_WRITE_MEM 0x815252+#define TP_READ_MEM 0x80 /* Not used in this implementation */5353+5454+/*5555+* RAM Locations for properties5656+ */5757+#define TP_SENS 0x4A /* Sensitivity */5858+#define TP_MB 0x4C /* Read Middle Button Status (RO) */5959+#define TP_INERTIA 0x4D /* Negative Inertia */6060+#define TP_SPEED 0x60 /* Speed of TP Cursor */6161+#define TP_REACH 0x57 /* Backup for Z-axis press */6262+#define TP_DRAGHYS 0x58 /* Drag Hysteresis */6363+ /* (how hard it is to drag */6464+ /* with Z-axis pressed) */6565+6666+#define TP_MINDRAG 0x59 /* Minimum amount of force needed */6767+ /* to trigger dragging */6868+6969+#define TP_THRESH 0x5C /* Minimum value for a Z-axis press */7070+#define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */7171+#define TP_Z_TIME 0x5E /* How sharp of a press */7272+#define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */7373+7474+/*7575+ * Toggling Flag bits7676+ */7777+#define TP_TOGGLE 0x47 /* Toggle command */7878+7979+#define TP_TOGGLE_MB 0x23 /* Disable/Enable Middle Button */8080+#define TP_MASK_MB 0x018181+#define TP_TOGGLE_EXT_DEV 0x23 /* Toggle external device */8282+#define TP_MASK_EXT_DEV 0x028383+#define TP_TOGGLE_DRIFT 0x23 /* Drift Correction */8484+#define TP_MASK_DRIFT 0x808585+#define TP_TOGGLE_BURST 0x28 /* Burst Mode */8686+#define TP_MASK_BURST 0x808787+#define TP_TOGGLE_PTSON 0x2C /* Press to Select */8888+#define TP_MASK_PTSON 0x018989+#define TP_TOGGLE_HARD_TRANS 0x2C /* Alternate method to set Hard Transparency */9090+#define TP_MASK_HARD_TRANS 0x809191+#define TP_TOGGLE_TWOHAND 0x2D /* Two handed */9292+#define TP_MASK_TWOHAND 0x019393+#define TP_TOGGLE_STICKY_TWO 0x2D /* Sticky two handed */9494+#define TP_MASK_STICKY_TWO 0x049595+#define TP_TOGGLE_SKIPBACK 0x2D /* Suppress movement after drag release */9696+#define TP_MASK_SKIPBACK 0x089797+#define TP_TOGGLE_SOURCE_TAG 0x20 /* Bit 3 of the first packet will be set to9898+ to the origin of the packet (external or TP) */9999+#define TP_MASK_SOURCE_TAG 0x80100100+#define TP_TOGGLE_EXT_TAG 0x22 /* Bit 3 of the first packet coming from the101101+ external device will be forced to 1 */102102+#define TP_MASK_EXT_TAG 0x04103103+104104+105105+/* Power on Self Test Results */106106+#define TP_POR_SUCCESS 0x3B107107+108108+/*109109+ * Default power on values110110+ */111111+#define TP_DEF_SENS 0x80112112+#define TP_DEF_INERTIA 0x06113113+#define TP_DEF_SPEED 0x61114114+#define TP_DEF_REACH 0x0A115115+116116+#define TP_DEF_DRAGHYS 0xFF117117+#define TP_DEF_MINDRAG 0x14118118+119119+#define TP_DEF_THRESH 0x08120120+#define TP_DEF_UP_THRESH 0xFF121121+#define TP_DEF_Z_TIME 0x26122122+#define TP_DEF_JENKS_CURV 0x87123123+124124+/* Toggles */125125+#define TP_DEF_MB 0x00126126+#define TP_DEF_PTSON 0x00127127+#define TP_DEF_SKIPBACK 0x00128128+#define TP_DEF_EXT_DEV 0x01129129+130130+#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))131131+132132+struct trackpoint_data133133+{134134+ unsigned char sensitivity, speed, inertia, reach;135135+ unsigned char draghys, mindrag;136136+ unsigned char thresh, upthresh;137137+ unsigned char ztime, jenks;138138+139139+ unsigned char press_to_select;140140+ unsigned char skipback;141141+142142+ unsigned char ext_dev;143143+};144144+145145+extern int trackpoint_detect(struct psmouse *psmouse, int set_properties);146146+147147+#endif /* _TRACKPOINT_H */