Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S263028AbVBCWxW (ORCPT ); Thu, 3 Feb 2005 17:53:22 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S261765AbVBCWxV (ORCPT ); Thu, 3 Feb 2005 17:53:21 -0500 Received: from wproxy.gmail.com ([64.233.184.196]:53419 "EHLO wproxy.gmail.com") by vger.kernel.org with ESMTP id S263028AbVBCWna (ORCPT ); Thu, 3 Feb 2005 17:43:30 -0500 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:reply-to:to:subject:cc:mime-version:content-type:content-transfer-encoding; b=U5lUAVO2aIGaZtPAs7au8pyXS0Iiws6gI5cqnAgh9Ac2w/T8F/IM3oFwX9co9avEE6l4djZ9gfgOsjGufVgyhOHyYCRj2HfhX/EP4yXfAMm4xgeuSXsHumkXGdc2/cpGeqqJYFHA5lZfrk9r2axDIrAyE7DwnAWb4jymbkBpnUU= Message-ID: Date: Thu, 3 Feb 2005 17:43:29 -0500 From: Stephen Evanchik Reply-To: Stephen Evanchik To: Vojtech Pavlik Subject: [PATCH 2.6.11-rc3] IBM Trackpoint support Cc: linux-kernel@vger.kernel.org Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 27688 Lines: 915 Vojtech, Here is a patch that exposes the IBM TrackPoint's extended properties as well as scroll wheel emulation. I would appreciate comments and suggestions to make this more acceptable. Stephen diff -uNr a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile --- a/drivers/input/mouse/Makefile 2005-02-03 17:30:40.000000000 -0500 +++ b/drivers/input/mouse/Makefile 2005-02-03 17:29:42.000000000 -0500 @@ -14,4 +14,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o +psmouse-objs := psmouse-base.o alps.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 2005-02-03 17:30:40.000000000 -0500 +++ b/drivers/input/mouse/psmouse-base.c 2005-02-03 17:29:42.000000000 -0500 @@ -23,6 +23,7 @@ #include "psmouse.h" #include "synaptics.h" #include "logips2pp.h" +#include "trackpoint.h" #include "alps.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -119,6 +120,13 @@ } /* + * TrackPoint scroll simulation handler if the BTN_MIDDLE is down + */ + + if(psmouse->model == PSMOUSE_TRACKPOINT) + trackpoint_sim_scroll(psmouse); + +/* * Generic PS/2 Mouse */ @@ -482,6 +490,16 @@ return PSMOUSE_IMPS; /* + * Try to initialize the IBM TrackPoint + */ + if (max_proto > PSMOUSE_PS2 && trackpoint_init(psmouse) == 0) { + psmouse->vendor = "IBM"; + psmouse->name = "TrackPoint"; + + return PSMOUSE_PS2; + } + +/* * Okay, all failed, we have a standard mouse here. The number of the buttons * is still a question, though. We assume 3. */ 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 2005-02-03 17:29:42.000000000 -0500 @@ -0,0 +1,649 @@ +/* + * 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. + * + * 29/01/2005 - Fixed UltraNav support + * Moved to libps2 interface + * Renamed internal property variables to be consistent with reference docs + * Fixed negative inertia not being set properly + * Added middle button scroll module parameter + * + */ + +#include +#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_reach = TP_DEF_REACH; +module_param_named(reach, tp_reach, uint, 0); +MODULE_PARM_DESC(reach, "Backup Range"); + +int tp_draghys = TP_DEF_DRAGHYS; +module_param_named(draghys, tp_draghys, uint, 0); +MODULE_PARM_DESC(draghys, "Resistance to dragging"); + +int tp_mindrag = TP_DEF_MINDRAG; +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_ptson = TP_DEF_PTSON; +module_param_named(ptson, tp_ptson, uint, 0); +MODULE_PARM_DESC(ptson, "Press to Select"); + +int tp_mb = TP_DEF_MB; +module_param_named(mb, tp_mb, uint, 0); +MODULE_PARM_DESC(mb, "Middle button is disabled"); + +int tp_mb_scroll = TP_DEF_MB_SCROLL; +module_param_named(mb_scroll, tp_mb_scroll, uint, 0); +MODULE_PARM_DESC(mb_scroll, "Scroll with middle button"); + + +__obsolete_setup("pts="); +__obsolete_setup("backup="); +__obsolete_setup("draghyst="); + +/* + * Device IO: read, write and toggle bit + */ +static void trackpoint_command(struct ps2dev *ps2dev, unsigned char cmd) +{ + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, cmd)); +} + +static void trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results) +{ + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)); + ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc)); +} + +static void trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val) +{ + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val)); +} + +static int trackpoint_toggle_bit(struct ps2dev *ps2dev, 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; + + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask)); + + 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, "%lu\n", (unsigned long)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(&psmouse->ps2dev, 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->ps2dev, 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_INERTIA); +MAKE_PROC_READ(PROC_READ_NAME(neg_inertia), inertia); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(backup), reach, TP_REACH); +MAKE_PROC_READ(PROC_READ_NAME(backup), reach); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(drag_hyst), draghys, TP_DRAGHYS); +MAKE_PROC_READ(PROC_READ_NAME(drag_hyst), draghys); + +MAKE_PROC_WRITE(PROC_WRITE_NAME(min_drag), mindrag, TP_MINDRAG); +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_PTSON, TP_MASK_PTSON); +MAKE_PROC_READ(PROC_READ_NAME(ptson), ptson); + +MAKE_PROC_TOGGLE(PROC_TOGGLE_NAME(skip_back), skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); +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); + +MAKE_PROC_TOGGLE(PROC_TOGGLE_NAME(ext_dev), ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); +MAKE_PROC_READ(PROC_READ_NAME(ext_dev), ext_dev); + +/* MAKE_PROC_WRITE( ) for Soft Transparent mode */ +static int transparent_write_func(struct file *file, const char __user *buffer, unsigned long count, void *data) +{ + int len = count; + unsigned char command; + 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->transparent = simple_strtoul(tmp, 0, 10); + command = (tp->transparent) ? TP_SET_SOFT_TRANS : TP_CANCEL_SOFT_TRANS; + + trackpoint_command(&psmouse->ps2dev, command); + return len; +} + +MAKE_PROC_READ(PROC_READ_NAME(transparent), transparent); + +/* MAKE_PROC_WRITE( ) for Middle Button Scroll mode */ +static int scroll_write_func(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->mb_scroll = simple_strtoul(tmp, 0, 10); + + return len; +} + +MAKE_PROC_READ(PROC_READ_NAME(scroll), mb_scroll); + +/* MAKE_PROC_WRITE( ) for delay before scroll */ +static int scroll_delay_write_func(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->scroll_delay = simple_strtoul(tmp, 0, 10); + + return len; +} + +MAKE_PROC_READ(PROC_READ_NAME(scroll_delay), scroll_delay); + + + +#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); + NEW_PROC_TOGGLE_ENTRY(ext_dev); + + /* Soft Transparent mode isn't a toggle or a single + * command used to read/write the value + */ + entry = create_proc_entry("transparent", 0644, tp_dir); + if(!entry) + goto no_transparent; + entry->owner = THIS_MODULE; + entry->data = psmouse; + entry->read_proc = transparent_read_func; + entry->write_proc = transparent_write_func; + + entry = create_proc_entry("scroll", 0644, tp_dir); + if(!entry) + goto no_scroll; + entry->owner = THIS_MODULE; + entry->data = psmouse; + entry->read_proc = scroll_read_func; + entry->write_proc = scroll_write_func; + + entry = create_proc_entry("scroll_delay", 0644, tp_dir); + if(!entry) + goto no_scroll_delay; + entry->owner = THIS_MODULE; + entry->data = psmouse; + entry->read_proc = scroll_delay_read_func; + entry->write_proc = scroll_delay_write_func; + + return 0; + +no_scroll_delay: + remove_proc_entry("scroll_delay", tp_dir); + +no_scroll: + remove_proc_entry("transparent", tp_dir); + +no_transparent: + remove_proc_entry("ext_dev", tp_dir); + +no_ext_dev: + remove_proc_entry("mb", tp_dir); + +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("scroll_delay", tp_dir); + remove_proc_entry("scroll", tp_dir); + remove_proc_entry("transparent", tp_dir); + remove_proc_entry("ext_dev", tp_dir); + 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) { } +#endif + + +/* This is much cleaner now, it probably could be better. + * The only thing left here is to make the scroll feature more gradual. + */ + +void trackpoint_sim_scroll(struct psmouse *psmouse) +{ + int diff; + struct trackpoint_data *tp = psmouse->private; + unsigned char *packet = psmouse->packet; + + if(!tp->mb_scroll) + return; + + if( ((packet[0] >> 2) & 1) == 0 ) { + + if(tp->mb_was_down && + time_after(tp->last_mb_press + msecs_to_jiffies(tp->scroll_delay), jiffies)) { + + /* This doesn't seem to get processed until the next + * mouse move. + */ + input_report_key(&psmouse->dev, BTN_MIDDLE, 1); + + input_sync(&psmouse->dev); + } + + tp->scrolling = 0; + tp->mb_was_down = 0; + } + else if(tp->scrolling) { + + /* Vertical scrolling */ + diff = (int) ((packet[0] << 3) & 0x100) - (int) packet[2]; + if( diff < -2 ) { + input_report_rel(&psmouse->dev, REL_WHEEL, 1); + } + else if(diff > 2) { + input_report_rel(&psmouse->dev, REL_WHEEL, -1); + } + + /* Horizontal scrolling */ + diff = (int) packet[1] - (int) ((packet[0] << 4) & 0x100); + if( diff < -2) { + input_report_rel(&psmouse->dev, REL_HWHEEL, 1); + } + else if( diff > 2) { + input_report_rel(&psmouse->dev, REL_HWHEEL, -1); + } + + packet[1] &= 0x00; + packet[2] &= 0x00; + } + else { + /* Middle button is down, but we aren't scrolling */ + if( time_after_eq(jiffies, tp->last_mb_press + msecs_to_jiffies(tp->scroll_delay)) ) + tp->scrolling = 1; + + tp->last_mb_press = jiffies; + tp->mb_was_down = 1; + } + + /* Suppress the key event from entering the queue */ + packet[0] &= 0xFB; +} + +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->ps2dev, TP_SENS, tp->sens); + trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia); + trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed); + + trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach); + trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys); + trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag); + + trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh); + trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->up_thresh); + + trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->z_time); + trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks_curv); + + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle); + if(((toggle & TP_MASK_PTSON) == TP_MASK_PTSON)!= tp->ptson) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle); + if(((toggle & TP_MASK_MB) == TP_MASK_MB) != tp->mb) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle); + if(((toggle & TP_MASK_TWOHAND) == TP_MASK_TWOHAND) != tp->twohand) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle); + if(((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle); + if(((toggle & TP_MASK_MB) == TP_MASK_MB) != tp->mb) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle); + if(((toggle & TP_MASK_SOURCE_TAG) == TP_MASK_SOURCE_TAG) != tp->source_tag) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG); + + trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle); + if(((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->skipback) + trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV); + + return 0; +} + +static void trackpoint_defaults(struct trackpoint_data *tp) +{ + tp->ptson = tp_ptson; + tp->sens = tp_sens; + tp->speed = tp_speed; + tp->reach = tp_reach; + + tp->draghys = tp_draghys; + tp->mindrag = tp_mindrag; + + tp->thresh = tp_thresh; + tp->up_thresh = tp_upthresh; + + tp->z_time = tp_ztime; + tp->jenks_curv = tp_jenks; + + tp->mb = tp_mb; + tp->mb_scroll = tp_mb_scroll; + + /* The following can't be set via module parameters */ + tp->inertia = TP_DEF_INERTIA; + tp->skipback = TP_DEF_SKIPBACK; + tp->ext_dev = TP_DEF_EXT_DEV; + tp->scroll_delay = TP_DEF_SCROLL_DELAY; + + tp->scrolling = tp->mb_was_down = 0; + tp->xacc = tp->yacc = 0; +} + + + +int trackpoint_init(struct psmouse *psmouse) +{ + unsigned char param[2]; + struct trackpoint_data *priv; + struct ps2dev *ps2dev = &psmouse->ps2dev; + + param[0] = param[1] = 0; + + /* The real driver disables, queries and + then enables so we'll do that too + */ + ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); + + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_DISABLE)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_DISABLE_EXT)); + + ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)); + + if(param[0] != TP_MAGIC_IDENT) + return -1; + + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_ENABLE_EXT)); + ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, 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]; + trackpoint_defaults(priv); + + trackpoint_reconnect(psmouse); + trackpoint_proc_init(psmouse); + + + /* Used to simulate wheel scrolling */ + set_bit(REL_HWHEEL, psmouse->dev.relbit); + set_bit(REL_WHEEL, psmouse->dev.relbit); + + psmouse->model = PSMOUSE_TRACKPOINT; + + psmouse->reconnect = trackpoint_reconnect; + psmouse->disconnect = trackpoint_disconnect; + + 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 2005-02-03 17:29:42.000000000 -0500 @@ -0,0 +1,170 @@ +/* + * 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 */ +#define TP_DISABLE_EXT (0x40) /* Disable external pointing device */ +#define TP_ENABLE_EXT (0x41) /* Enable external pointing device */ + +/* + * Mode manipulation + */ +#define TP_SET_SOFT_TRANS (0x4E) /* Set mode */ +#define TP_CANCEL_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_INERTIA (0x4D) /* Negative Inertia */ +#define TP_SPEED (0x60) /* Speed of TP Cursor */ +#define TP_REACH (0x57) /* Backup for Z-axis press */ +#define TP_DRAGHYS (0x58) /* Drag Hysteresis */ + /* (how hard it is to drag */ + /* with Z-axis pressed) */ + +#define TP_MINDRAG (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_PTSON (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_SKIPBACK (0x2D) /* Suppress movement */ + /* after drag release */ +#define TP_TOGGLE_EXT_DEV (0x23) /* Toggle external device */ +#define TP_TOGGLE_SOURCE_TAG (0x20) /* Bit 3 of the first packet will be set to + to the origin of the packet (external or TP) */ + +/* + * Various makses for registers + * XOR'd to current contents for new value + */ +#define TP_MASK_PTSON (0x01) +#define TP_MASK_SKIPBACK (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) +#define TP_MASK_EXT_DEV (0x02) +#define TP_MASK_SOURCE_TAG (0x80) + +/* Power on Self Test Results */ +#define TP_POR_SUCCESS (0x3B) + +/* + * Default power on values + */ +#define TP_DEF_SENS (0x80) +#define TP_DEF_INERTIA (0x06) +#define TP_DEF_SPEED (0x61) +#define TP_DEF_REACH (0x0A) + +#define TP_DEF_DRAGHYS (0xFF) +#define TP_DEF_MINDRAG (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_PTSON (0x00) +#define TP_DEF_SKIPBACK (0x00) +#define TP_DEF_EXT_DEV (0x01) +#define TP_DEF_MB_SCROLL (0x00) +#define TP_DEF_SCROLL_DELAY (200) + +#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) + +#define PSMOUSE_TRACKPOINT 42 +#define Z_ACCEL_EXP 1.2 +#define Z_ACCEL_MULT 0.02 + + +struct trackpoint_data +{ + unsigned char firmware_id; + + 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; + + unsigned char ext_dev; + unsigned char transparent; + unsigned char source_tag; + + unsigned char mb_scroll, mb_was_down, scrolling; + unsigned long scroll_delay, last_mb_press; + + int xacc, yacc; +}; + +extern int trackpoint_init (struct psmouse *psmouse); +extern void trackpoint_sim_scroll(struct psmouse *psmouse); + +#endif /* _TRACKPOINT_H */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/