diff -uNr a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile --- a/drivers/input/mouse/Makefile 2004-10-18 17:53:43.000000000 -0400 +++ b/drivers/input/mouse/Makefile 2004-10-31 12:27:45.000000000 -0500 @@ -14,4 +14,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -psmouse-objs := psmouse-base.o logips2pp.o synaptics.o +psmouse-objs := psmouse-base.o logips2pp.o synaptics.o trackpoint.o diff -uNr a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c --- a/drivers/input/mouse/psmouse-base.c 2004-10-18 17:53:43.000000000 -0400 +++ b/drivers/input/mouse/psmouse-base.c 2004-11-07 00:28:29.000000000 -0500 @@ -21,6 +21,7 @@ #include "psmouse.h" #include "synaptics.h" #include "logips2pp.h" +#include "trackpoint.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -468,6 +469,16 @@ int synaptics_hardware = 0; /* + * Try to initialize the IBM TrackPoint + */ + if (max_proto > PSMOUSE_PS2 && trackpoint_init(psmouse) == 0) { + psmouse->vendor = "IBM"; + psmouse->name = "TrackPoint"; + + return PSMOUSE_PS2; + } + +/* * Try Synaptics TouchPad */ if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) { diff -uNr a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c --- a/drivers/input/mouse/trackpoint.c 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/input/mouse/trackpoint.c 2004-12-01 18:52:16.000000000 -0500 @@ -0,0 +1,424 @@ +/* + * Stephen Evanchik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Trademarks are the property of their respective owners. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "psmouse.h" +#include "trackpoint.h" + + +int tp_sens = TP_DEF_SENS; +module_param_named(sens, tp_sens, uint, 0); +MODULE_PARM_DESC(sens, "Sensitivity"); + +int tp_speed = TP_DEF_SPEED; +module_param_named(speed, tp_speed, uint, 0); +MODULE_PARM_DESC(speed, "Speed of pointer"); + +int tp_backup = TP_DEF_BACKUP; +module_param_named(backup, tp_backup, uint, 0); +MODULE_PARM_DESC(backup, "Backup Range"); + +int tp_draghyst = TP_DEF_DRAG_HYST; +module_param_named(draghyst, tp_draghyst, uint, 0); +MODULE_PARM_DESC(draghyst, "Resistance to dragging"); + +int tp_mindrag = TP_DEF_MIN_DRAG; +module_param_named(mindrag, tp_mindrag, uint, 0); +MODULE_PARM_DESC(mindrag, "Drag threshold"); + +int tp_thresh = TP_DEF_THRESH; +module_param_named(thresh, tp_thresh, uint, 0); +MODULE_PARM_DESC(thresh, "Force necessary to trigger a press or release"); + +int tp_upthresh = TP_UP_THRESH; +module_param_named(upthresh, tp_upthresh, uint, 0); +MODULE_PARM_DESC(upthresh, "Force necessary to trigger a click"); + +int tp_ztime = TP_DEF_Z_TIME; +module_param_named(ztime, tp_ztime, uint, 0); +MODULE_PARM_DESC(ztime, "Determines how sharp a press is"); + +int tp_jenks = TP_DEF_JENKS_CURV; +module_param_named(jenks, tp_jenks, uint, 0); +MODULE_PARM_DESC(jenks, "Double click sensitivity"); + + +/* Toggles */ +int tp_pts = TP_DEF_PTS; +module_param_named(pts, tp_pts, uint, 0); +MODULE_PARM_DESC(pts, "Press to Select"); + +int tp_mb = TP_DEF_MB; +module_param_named(mb, tp_mb, uint, 0); +MODULE_PARM_DESC(pts, "Middle button is disabled"); + +/* + * Device IO: read, write and toggle bit + */ +static void trackpoint_read(struct psmouse *psmouse, unsigned char loc, unsigned char *results) +{ + psmouse_command(psmouse, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)); + psmouse_command(psmouse, results, MAKE_PS2_CMD(0, 1, loc)); +} + +static void trackpoint_write(struct psmouse *psmouse, unsigned char loc, unsigned char val) +{ + psmouse_command(psmouse, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)); + psmouse_command(psmouse, NULL, MAKE_PS2_CMD(0,0, TP_WRITE_MEM)); + psmouse_command(psmouse, &val, MAKE_PS2_CMD(1,0, loc)); +} + +static int trackpoint_toggle_bit(struct psmouse *psmouse, unsigned char loc, unsigned char mask) +{ + /* Bad things will happen if the loc param isn't in this range */ + if(loc < 0x20 || loc >= 0x2F) + return -1; + + psmouse_command(psmouse, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)); + psmouse_command(psmouse, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)); + psmouse_command(psmouse, &mask, MAKE_PS2_CMD(1, 0, loc)); + + return 0; +} + + +#ifdef CONFIG_PROC_FS + +#define PROC_READ_NAME(name) name##_read_func +#define PROC_WRITE_NAME(name) name##_write_func +#define PROC_TOGGLE_NAME(name) name##_toggle_func + +#define MAKE_PROC_READ(name, item) \ + static int name(char* page, char** start, off_t off, int count, int* eof, void* data) \ + { \ + int len; \ + struct psmouse *psmouse = (struct psmouse *)data; \ + struct trackpoint_data *tp = (struct trackpoint_data*)psmouse->private; \ + len = sprintf(page, "%d\n", tp->item); \ + *eof = 1; \ + return len; \ + } + +#define MAKE_PROC_WRITE(name, item, command) \ + static int name(struct file *file, const char __user *buffer, unsigned long count, void *data) \ + { \ + int len = count; \ + unsigned char tmp[5]; \ + struct psmouse *psmouse = (struct psmouse *)data; \ + struct trackpoint_data *tp = (struct trackpoint_data*)psmouse->private; \ + if(count > sizeof(tmp) - 1) \ + len = sizeof(tmp) - 1; \ + if(copy_from_user(tmp, buffer, len)) \ + return -EFAULT; \ + tmp[len] = '\0'; \ + tp->item = simple_strtoul(tmp, 0, 10); \ + trackpoint_write((struct psmouse *)data, command, tp->item); \ + return len; \ + } + +#define MAKE_PROC_TOGGLE(name, item, command, mask) \ + static int name(struct file *file, const char __user *buffer, unsigned long count, void *data) \ + { \ + int len = count; \ + unsigned char toggle, tmp[5]; \ + struct psmouse *psmouse = (struct psmouse *)data; \ + struct trackpoint_data *tp = (struct trackpoint_data*)psmouse->private; \ + if(count > sizeof(tmp) - 1) \ + len = sizeof(tmp) - 1; \ + if(copy_from_user(tmp, buffer, len)) \ + return -EFAULT; \ + tmp[len] = '\0'; \ + toggle = (tmp[0] == '1') ? 1 : 0; \ + if( toggle != tp->item) { \ + tp->item = toggle; \ + trackpoint_toggle_bit(psmouse, command, mask); \ + } \ + return len; \ + } + + +MAKE_PROC_WRITE(PROC_WRITE_NAME(sensitivity), sens, TP_SENS); +MAKE_PROC_READ(PROC_READ_NAME(sensitivity), sens); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(speed), speed, TP_SPEED); +MAKE_PROC_READ(PROC_READ_NAME(speed), speed); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(neg_inertia), inertia, TP_NEG_INERT); +MAKE_PROC_READ(PROC_READ_NAME(neg_inertia), inertia); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(backup), reach, TP_BACKUP); +MAKE_PROC_READ(PROC_READ_NAME(backup), reach); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(drag_hyst), draghys, TP_DRAG_HYST); +MAKE_PROC_READ(PROC_READ_NAME(drag_hyst), draghys); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(min_drag), mindrag, TP_MIN_DRAG); +MAKE_PROC_READ(PROC_READ_NAME(min_drag), mindrag); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(thresh), thresh, TP_THRESH); +MAKE_PROC_READ(PROC_READ_NAME(thresh), thresh); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(up_thresh), up_thresh, TP_UP_THRESH); +MAKE_PROC_READ(PROC_READ_NAME(up_thresh), up_thresh); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(z_time), z_time, TP_Z_TIME); +MAKE_PROC_READ(PROC_READ_NAME(z_time), z_time); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(jenks_curv), jenks_curv, TP_JENKS_CURV); +MAKE_PROC_READ(PROC_READ_NAME(jenks_curv), jenks_curv); + +MAKE_PROC_TOGGLE(PROC_TOGGLE_NAME(ptson), ptson, TP_TOGGLE_PTS, TP_MASK_PTS); +MAKE_PROC_READ(PROC_READ_NAME(ptson), ptson); + +MAKE_PROC_TOGGLE(PROC_TOGGLE_NAME(skip_back), skipback, TP_TOGGLE_SKIP_BACK, TP_MASK_SKIP_BACK); +MAKE_PROC_READ(PROC_READ_NAME(skip_back), skipback); + +MAKE_PROC_TOGGLE(PROC_TOGGLE_NAME(mb), mb, TP_TOGGLE_MB, TP_MASK_MB); +MAKE_PROC_READ(PROC_READ_NAME(mb), mb); + + + +#define NEW_PROC_ENTRY(name) \ + entry = create_proc_entry(#name, 0644, tp_dir); \ + if(!entry) \ + goto no_##name; \ + entry->owner = THIS_MODULE; \ + entry->data = psmouse; \ + entry->read_proc = PROC_READ_NAME(name); \ + entry->write_proc = PROC_WRITE_NAME(name); + + +#define NEW_PROC_TOGGLE_ENTRY(name) \ + entry = create_proc_entry(#name, 0644, tp_dir); \ + if(!entry) \ + goto no_##name; \ + entry->owner = THIS_MODULE; \ + entry->data = psmouse; \ + entry->read_proc = PROC_READ_NAME(name); \ + entry->write_proc = PROC_TOGGLE_NAME(name); + + + +static struct proc_dir_entry *tp_dir = NULL; + + +static int trackpoint_proc_init(struct psmouse *psmouse) +{ + struct proc_dir_entry *entry = NULL; + + tp_dir = proc_mkdir("trackpoint", NULL); + if(!tp_dir) + return -ENOMEM; + + tp_dir->owner = THIS_MODULE; + + NEW_PROC_ENTRY(sensitivity); + NEW_PROC_ENTRY(speed); + NEW_PROC_ENTRY(neg_inertia); + NEW_PROC_ENTRY(backup); + NEW_PROC_ENTRY(drag_hyst); + NEW_PROC_ENTRY(min_drag); + NEW_PROC_ENTRY(thresh); + NEW_PROC_ENTRY(up_thresh); + NEW_PROC_ENTRY(z_time); + NEW_PROC_ENTRY(jenks_curv); + + NEW_PROC_TOGGLE_ENTRY(ptson); + NEW_PROC_TOGGLE_ENTRY(skip_back); + NEW_PROC_TOGGLE_ENTRY(mb); + + return 0; + +no_mb: + remove_proc_entry("skip_back", tp_dir); + +no_skip_back: + remove_proc_entry("ptson", tp_dir); + +no_ptson: + remove_proc_entry("jenks_curv", tp_dir); + +no_jenks_curv: + remove_proc_entry("z_time", tp_dir); + +no_z_time: + remove_proc_entry("up_thresh", tp_dir); + +no_up_thresh: + remove_proc_entry("thresh", tp_dir); + +no_thresh: + remove_proc_entry("min_drag", tp_dir); + +no_min_drag: + remove_proc_entry("drag_hyst", tp_dir); + +no_drag_hyst: + remove_proc_entry("backup", tp_dir); + +no_backup: + remove_proc_entry("neg_inertia", tp_dir); + +no_neg_inertia: + remove_proc_entry("speed", tp_dir); + +no_speed: + remove_proc_entry("sensitivity", tp_dir); + +no_sensitivity: + remove_proc_entry("trackpoint", NULL); + + return -ENOMEM; +} + +static void trackpoint_proc_remove(void) +{ + remove_proc_entry("mb", tp_dir); + remove_proc_entry("skip_back", tp_dir); + remove_proc_entry("ptson", tp_dir); + remove_proc_entry("jenks_curv", tp_dir); + remove_proc_entry("z_time", tp_dir); + remove_proc_entry("up_thresh", tp_dir); + remove_proc_entry("thresh", tp_dir); + remove_proc_entry("min_drag", tp_dir); + remove_proc_entry("drag_hyst", tp_dir); + remove_proc_entry("backup", tp_dir); + remove_proc_entry("neg_inertia", tp_dir); + remove_proc_entry("speed", tp_dir); + remove_proc_entry("sensitivity", tp_dir); + remove_proc_entry("trackpoint", NULL); +} + +#else +static int trackpoint_proc_init(struct psmouse *psmouse) { return 0; } +static void trackpoint_proc_remove(void) { do {} while(0); } +#endif + + +void trackpoint_disconnect(struct psmouse *psmouse) +{ + trackpoint_proc_remove(); + + kfree(psmouse->private); +} + +int trackpoint_reconnect(struct psmouse *psmouse) +{ + unsigned char toggle; + struct trackpoint_data *tp = psmouse->private; + + /* Push the config to the device */ + + trackpoint_write(psmouse, TP_SENS, tp->sens); + trackpoint_write(psmouse, TP_NEG_INERT, tp->inertia); + trackpoint_write(psmouse, TP_SPEED, tp->speed); + + trackpoint_write(psmouse, TP_BACKUP, tp->reach); + trackpoint_write(psmouse, TP_DRAG_HYST, tp->draghys); + trackpoint_write(psmouse, TP_MIN_DRAG, tp->mindrag); + + trackpoint_write(psmouse, TP_THRESH, tp->thresh); + trackpoint_write(psmouse, TP_UP_THRESH, tp->up_thresh); + + trackpoint_write(psmouse, TP_Z_TIME, tp->z_time); + trackpoint_write(psmouse, TP_JENKS_CURV, tp->jenks_curv); + + + trackpoint_read(psmouse, TP_TOGGLE_PTS, &toggle); + if(((toggle & TP_MASK_PTS) == TP_MASK_PTS)!= tp->ptson) + trackpoint_toggle_bit(psmouse, TP_TOGGLE_PTS, TP_MASK_PTS); + + trackpoint_read(psmouse, TP_TOGGLE_MB, &toggle); + if(((toggle & TP_MASK_MB) == TP_MASK_MB) != tp->mb) + trackpoint_toggle_bit(psmouse, TP_TOGGLE_MB, TP_MASK_MB); + + trackpoint_read(psmouse, TP_TOGGLE_SKIP_BACK, &toggle); + if(((toggle & TP_MASK_SKIP_BACK) == TP_MASK_SKIP_BACK) != tp->skipback) + trackpoint_toggle_bit(psmouse, TP_TOGGLE_SKIP_BACK, TP_MASK_SKIP_BACK); + + /* TODO: Add external device pass through */ + + return 0; +} + +static void trackpoint_defaults(struct trackpoint_data *tp) +{ + tp->sens = tp_sens; + tp->speed = tp_speed; + tp->reach = tp_backup; + + tp->draghys = tp_draghyst; + tp->mindrag = tp_mindrag; + + tp->thresh = tp_thresh; + tp->up_thresh = tp_upthresh; + + tp->z_time = tp_ztime; + tp->jenks_curv = tp_jenks; + + tp->ptson = tp_pts; + tp->mb = tp_mb; + tp->skipback = TP_DEF_SKIP_BACK; +} + + + +int trackpoint_init(struct psmouse *psmouse) +{ + unsigned char param[2]; + struct trackpoint_data *priv; + + param[0] = param[1] = 0; + + /* The real driver disables, queries and + then enables so we'll do that too + */ + psmouse_command(psmouse, param, MAKE_PS2_CMD(0, 2, TP_DISABLE)); + + psmouse_command(psmouse, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)); + if(param[0] != TP_MAGIC_IDENT) + return -1; + + psmouse_command(psmouse, param, MAKE_PS2_CMD(0, 2, TP_ENABLE)); + + psmouse->private = priv = kmalloc(sizeof(struct trackpoint_data), GFP_KERNEL); + + if(!priv) + return -1; + + memset(priv, 0, sizeof(struct trackpoint_data)); + + priv->firmware_id = param[1]; + + + psmouse->reconnect = trackpoint_reconnect; + psmouse->disconnect = trackpoint_disconnect; + + /* + * Initialize the device's default settings + */ + trackpoint_defaults(priv); + trackpoint_reconnect(psmouse); + + trackpoint_proc_init(psmouse); + + printk("IBM TrackPoint firmware: 0x%02X\n", param[1]); + + return 0; +} + + diff -uNr a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h --- a/drivers/input/mouse/trackpoint.h 1969-12-31 19:00:00.000000000 -0500 +++ b/drivers/input/mouse/trackpoint.h 2004-12-01 18:59:01.000000000 -0500 @@ -0,0 +1,151 @@ +/* + * IBM TrackPoint PS/2 mouse driver + * + * Stephen Evanchik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#ifndef _TRACKPOINT_H +#define _TRACKPOINT_H + +/* + * These constants are from the TrackPoint System + * Engineering documentation Version 4 from IBM Watson + * research: + * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html + */ + +#define TP_DISABLE (0xF5) +#define TP_ENABLE (0xF4) + +#define TP_READ_ID (0xE1) /* Sent for device identification */ +#define TP_MAGIC_IDENT (0x01) /* Sent after a TP_READ_ID followed */ + /* by the firmware ID */ + +#define TP_COMMAND (0xE2) /* Commands start with this */ + + +/* + * Commands + */ +#define TP_RECALIB (0x51) /* Recalibrate */ +#define TP_POWER_DOWN (0x44) /* Can only be undone through HW reset */ +#define TP_EXT_DEV (0x21) /* Determines if external device is connected (RO) */ +#define TP_EXT_BTN (0x4B) /* Read extended button status */ +#define TP_POR (0x7F) /* Execute Power on Reset */ +#define TP_POR_RESULTS (0x25) /* Read Power on Self test results */ + +/* + * Mode manipulation + */ +#define TP_SET_SOFT_TRANS (0x4E) /* Set mode */ +#define TP_CAN_SOFT_TRANS (0xB9) /* Cancel mode */ +#define TP_SET_HARD_TRANS (0x45) /* Mode can only be set */ + + +/* + * Register oriented commands/properties + */ +#define TP_WRITE_MEM (0x81) +#define TP_READ_MEM (0x80) /* Not used in this implementation */ + +/* +* RAM Locations for properties + */ +#define TP_SENS (0x4A) /* Sensitivity */ +#define TP_MB (0x4C) /* Read Middle Button Status (RO) */ +#define TP_NEG_INERT (0x4D) /* Negative Inertia */ +#define TP_SPEED (0x60) /* Speed of TP Cursor */ +#define TP_BACKUP (0x57) /* Backup for Z-axis press */ +#define TP_DRAG_HYST (0x58) /* Drag Hysteresis */ + /* (how hard it is to drag */ + /* with Z-axis pressed) */ + +#define TP_MIN_DRAG (0x59) /* Minimum amount of force needed */ + /* to trigger dragging */ + +#define TP_THRESH (0x5C) /* Minimum value for a Z-axis press */ +#define TP_UP_THRESH (0x5A) /* Used to generate a 'click' on Z-axis */ +#define TP_Z_TIME (0x5E) /* How sharp of a press */ +#define TP_JENKS_CURV (0x5D) /* Minimum curvature for double click */ + +/* + * Toggling Flag bits + */ +#define TP_TOGGLE (0x47) /* Toggle command */ + +#define TP_TOGGLE_MB (0x23) /* Disable/Enable Middle Button */ +#define TP_TOGGLE_DRIFT (0x23) /* Drift Correction */ +#define TP_TOGGLE_BURST (0x28) /* Burst Mode */ +#define TP_TOGGLE_PTS (0x2C) /* Press to Select */ +#define TP_TOGGLE_HARD_TRANS (0x2C) /* Alternate method to set Hard Transparency */ +#define TP_TOGGLE_TWOHAND (0x2D) /* Two handed */ +#define TP_TOGGLE_STICKY_TWO (0x2D) /* Sticky two handed */ +#define TP_TOGGLE_SKIP_BACK (0x2D) /* Suppress movement */ + /* after drag release */ + +/* + * Various makses for registers + * XOR'd to current contents for new value + */ +#define TP_MASK_PTS (0x01) +#define TP_MASK_SKIP_BACK (0x08) +#define TP_MASK_TWOHAND (0x01) +#define TP_MASK_STICKY_TWO (0x04) +#define TP_MASK_HARD_TRANS (0x80) +#define TP_MASK_BURST (0x80) +#define TP_MASK_MB (0x01) +#define TP_MASK_DRIFT (0x80) + +/* Power on Self Test Results */ +#define TP_POR_SUCCESS (0x3B) + +/* + * Default power on values + */ +#define TP_DEF_SENS (0x80) +#define TP_DEF_NEG_INT (0x06) +#define TP_DEF_SPEED (0x61) +#define TP_DEF_BACKUP (0x0A) + +#define TP_DEF_DRAG_HYST (0xFF) +#define TP_DEF_MIN_DRAG (0x14) + +#define TP_DEF_THRESH (0x08) +#define TP_DEF_UP_THRESH (0xFF) +#define TP_DEF_Z_TIME (0x26) +#define TP_DEF_JENKS_CURV (0x87) + +/* Toggles */ +#define TP_DEF_MB (0x00) +#define TP_DEF_PTS (0x00) +#define TP_DEF_SKIP_BACK (0x00) + +#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) + +enum +{ TP_SOFT_TRANS, TP_HARD_TRANS }; + +struct trackpoint_data +{ + unsigned char firmware_id; + + unsigned char mode; /* Transparency mode */ + + unsigned char sens, speed, inertia, reach; + unsigned char draghys, mindrag; + unsigned char thresh, up_thresh; + unsigned char z_time, jenks_curv; + + unsigned char ptson; /* Press to Select */ + unsigned char twohand, skipback; + unsigned char mb; +}; + +extern int trackpoint_init (struct psmouse *psmouse); + + +#endif /* _TRACKPOINT_H */