summaryrefslogtreecommitdiff
path: root/synaptics.c
diff options
context:
space:
mode:
Diffstat (limited to 'synaptics.c')
-rw-r--r--synaptics.c903
1 files changed, 903 insertions, 0 deletions
diff --git a/synaptics.c b/synaptics.c
new file mode 100644
index 0000000..0396fdb
--- /dev/null
+++ b/synaptics.c
@@ -0,0 +1,903 @@
+/* Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
+ *
+ * Copyright (c) 1999 Henry Davies <hdavies@ameritech.net> for the
+ * absolut to relative translation code (from the gpm-source)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+/*****************************************************************************
+ * Standard Headers
+ ****************************************************************************/
+
+#include <misc.h>
+#include <xf86.h>
+#define NEED_XF86_TYPES
+#include <xf86_ansic.h>
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+#include <xisb.h>
+#include <exevents.h> /* Needed for InitValuator/Proximity stuff */
+#include "mipointer.h"
+#include <xf86Optrec.h> /* needed for Options */
+
+/*****************************************************************************
+ * Local Headers
+ ****************************************************************************/
+#include "synaptics.h"
+#include "ps2comm.h"
+
+/*****************************************************************************
+ * Variables without includable headers
+ ****************************************************************************/
+
+/*****************************************************************************
+ * Local Variables
+ ****************************************************************************/
+
+typedef enum {
+ BOTTOM_EDGE = 1,
+ TOP_EDGE = 2,
+ LEFT_EDGE = 4,
+ RIGHT_EDGE = 8,
+ LEFT_BOTTOM_EDGE = BOTTOM_EDGE | LEFT_EDGE,
+ RIGHT_BOTTOM_EDGE = BOTTOM_EDGE | RIGHT_EDGE,
+ RIGHT_TOP_EDGE = TOP_EDGE | RIGHT_EDGE,
+ LEFT_TOP_EDGE = TOP_EDGE | LEFT_EDGE
+} edge_type;
+
+#define DIFF_TIME(a, b) (((a)>(b))?(a)-(b):(b)-(a))
+#define VERSION "0.10"
+
+static InputInfoPtr
+SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags);
+
+
+InputDriverRec SYNAPTICS = {
+ 1,
+ "synaptics",
+ NULL,
+ SynapticsPreInit,
+ /*SynapticsUnInit*/ NULL,
+ NULL,
+ 0
+};
+
+#ifdef XFree86LOADER
+
+static XF86ModuleVersionInfo VersionRec =
+{
+ "synaptics",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XF86_VERSION_CURRENT,
+ 1, 0, 0,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0} /* signature, to be patched into the file by
+ * a tool */
+};
+
+
+static pointer
+SetupProc(pointer module, pointer options, int *errmaj, int *errmin )
+{
+ xf86AddInputDriver(&SYNAPTICS, module, 0);
+ return module;
+}
+
+XF86ModuleData synapticsModuleData = {&VersionRec, &SetupProc, NULL };
+
+#endif /* XFree86LOADER */
+
+
+/*****************************************************************************
+ * Function Definitions
+ ****************************************************************************/
+
+static InputInfoPtr
+SynapticsPreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ LocalDevicePtr local;
+ SynapticsPrivatePtr priv;
+ XF86OptionPtr optList;
+ char *s;
+ int shmid;
+
+ /* allocate memory for SynaticsPrivateRec */
+ priv = xcalloc (1, sizeof (SynapticsPrivateRec));
+ if (!priv)
+ return NULL;
+
+ /* Allocate a new InputInfoRec and add it to the head xf86InputDevs. */
+ local = xf86AllocateInput(drv, 0);
+ if (!local) {
+ xfree(priv);
+ return NULL;
+ }
+
+ /* initialize the InputInfoRec */
+ local->name = dev->identifier;
+ local->type_name = XI_MOUSE; /* XI_TOUCHPAD and KDE killed the X-Server at startup ? */
+ local->device_control = DeviceControl;
+ local->read_input = ReadInput;
+ local->control_proc = ControlProc;
+ local->close_proc = CloseProc;
+ local->switch_mode = SwitchMode;
+ local->conversion_proc = ConvertProc;
+ local->reverse_conversion_proc = NULL;
+ local->dev = NULL;
+ local->private = priv;
+ local->private_flags = 0;
+ local->flags = XI86_POINTER_CAPABLE | XI86_SEND_DRAG_EVENTS;
+ local->conf_idev = dev;
+ local->motion_history_proc = xf86GetMotionEvents;
+ local->history_size = 0;
+ local->always_core_feedback = 0;
+
+ xf86CollectInputOptions(local, NULL, NULL);
+
+ xf86OptionListReport(local->options);
+
+ /* open the touchpad device */
+ local->fd = xf86OpenSerial (local->options);
+ if (local->fd == -1)
+ {
+ ErrorF ("Synaptics driver unable to open device\n");
+ goto SetupProc_fail;
+ }
+ xf86ErrorFVerb( 6, "port opened successfully\n" );
+
+ /* initialize variables */
+ priv->repeat_timer = NULL;
+ priv->repeatButtons = 0;
+
+ /* install shared memory or normal memory for parameter */
+ if(xf86SetBoolOption(local->options, "SHMConfig", FALSE)) {
+ xf86shmctl(SHM_SYNAPTICS, XF86IPC_RMID, NULL);
+ if((shmid = xf86shmget(SHM_SYNAPTICS, sizeof(SynapticsSHM), 0777 | XF86IPC_CREAT)) == -1) {
+ xf86Msg(X_ERROR, "%s error shmget\n", local->name);
+ goto SetupProc_fail;
+ } else if((priv->synpara = (SynapticsSHM*) xf86shmat(shmid, NULL, 0)) == NULL) {
+ xf86Msg(X_ERROR, "%s error shmat\n", local->name);
+ goto SetupProc_fail;
+ }
+ } else {
+ priv->synpara = xcalloc (1, sizeof (SynapticsSHM));
+ if(!priv->synpara)
+ goto SetupProc_fail;
+ }
+
+ /* read the parameter */
+ priv->synpara->left_edge = xf86SetIntOption(local->options, "LeftEdge", 1900);
+ priv->synpara->right_edge = xf86SetIntOption(local->options, "RightEdge", 5400);
+ priv->synpara->top_edge = xf86SetIntOption(local->options, "TopEdge", 3900);
+ priv->synpara->bottom_edge = xf86SetIntOption(local->options, "BottomEdge", 1800);
+ priv->synpara->finger_low = xf86SetIntOption(local->options, "FingerLow", 25);
+ priv->synpara->finger_high = xf86SetIntOption(local->options, "FingerHigh", 30);
+ priv->synpara->tap_time = xf86SetIntOption(local->options, "MaxTapTime", 20);
+ priv->synpara->tap_move = xf86SetIntOption(local->options, "MaxTapMove", 220);
+ priv->synpara->scroll_dist_vert = xf86SetIntOption(local->options, "VertScrollDelta", 100);
+ priv->synpara->repeater = xf86SetStrOption(local->options, "Repeater", NULL);
+ s = xf86FindOptionValue(local->options, "MinSpeed");
+ if((!s) || (xf86sscanf(s, "%lf", &priv->synpara->min_speed) != 1))
+ priv->synpara->min_speed=0.02;
+ s = xf86FindOptionValue(local->options, "MaxSpeed");
+ if((!s) || (xf86sscanf(s, "%lf", &priv->synpara->max_speed) != 1))
+ priv->synpara->max_speed=0.18;
+ s = xf86FindOptionValue(local->options, "AccelFactor");
+ if((!s) || (xf86sscanf(s, "%lf", &priv->synpara->accl) != 1))
+ priv->synpara->accl=0.0015;
+
+ priv->buffer = XisbNew(local->fd, 200);
+ DBG(9, XisbTrace (priv->buffer, 1));
+
+ if(priv->synpara->repeater) {
+ /* create repeater fifo */
+ if((xf86mknod(priv->synpara->repeater, 666, XF86_S_IFIFO) != 0) &&
+ (xf86errno != xf86_EEXIST)) {
+ xf86Msg(X_ERROR, "%s can't create repeater fifo\n", local->name);
+ xf86free(priv->synpara->repeater);
+ priv->synpara->repeater = NULL;
+ priv->fifofd = -1;
+ } else {
+ /* open the repeater fifo */
+ optList = xf86NewOption("Device", priv->synpara->repeater);
+ if((priv->fifofd = xf86OpenSerial(optList)) == -1) {
+ xf86Msg(X_ERROR, "%s repeater device open failed\n", local->name);
+ xf86free(priv->synpara->repeater);
+ priv->synpara->repeater = NULL;
+ priv->fifofd = -1;
+ }
+ }
+ }
+
+ if(QueryHardware(local) != Success) {
+ xf86Msg(X_ERROR, "%s Unable to query/initialize Synaptics hardware.\n", local->name);
+ goto SetupProc_fail;
+ }
+
+ local->history_size = xf86SetIntOption( local->options, "HistorySize", 0 );
+
+ /* this results in an xstrdup that must be freed later */
+ /*local->name = xf86SetStrOption( local->options, "DeviceName", "Synaptics-Touchpad" );*/
+ xf86ProcessCommonOptions(local, local->options);
+ local->flags |= XI86_CONFIGURED;
+
+ if (local->fd != -1) {
+ RemoveEnabledDevice (local->fd);
+ if (priv->buffer) {
+ XisbFree(priv->buffer);
+ priv->buffer = NULL;
+ }
+ xf86CloseSerial(local->fd);
+ }
+ RemoveEnabledDevice (local->fd);
+ local->fd = -1;
+ return (local);
+
+ SetupProc_fail:
+ if ((local) && (local->fd))
+ xf86CloseSerial (local->fd);
+
+ /* If it fails, the name will be printed
+ if ((local) && (local->name))
+ xfree (local->name);
+ */
+
+ if ((priv) && (priv->buffer))
+ XisbFree (priv->buffer);
+ if ((priv) && (priv->synpara))
+ xfree (priv->synpara);
+ if (priv)
+ xfree (priv);
+ return (local);
+}
+
+/*
+ * SynapticsCtrl --
+ * Alter the control parameters for the mouse. Note that all special
+ * protocol values are handled by dix.
+ */
+static void
+SynapticsCtrl(DeviceIntPtr device, PtrCtrl *ctrl)
+{
+ ErrorF("SynapticsCtrl called.\n");
+/*
+ pInfo = device->public.devicePrivate;
+ pMse = pInfo->private;
+
+ pMse->num = ctrl->num;
+ pMse->den = ctrl->den;
+ pMse->threshold = ctrl->threshold;
+*/
+}
+
+static Bool
+DeviceControl (DeviceIntPtr dev, int mode)
+{
+ Bool RetValue;
+
+ switch (mode)
+ {
+ case DEVICE_INIT:
+ DeviceInit(dev);
+ RetValue = Success;
+ break;
+ case DEVICE_ON:
+ RetValue = DeviceOn( dev );
+ break;
+ case DEVICE_OFF:
+ case DEVICE_CLOSE:
+ RetValue = DeviceOff( dev );
+ break;
+ default:
+ RetValue = BadValue;
+ }
+
+ return( RetValue );
+}
+
+static Bool
+DeviceOn (DeviceIntPtr dev)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ SynapticsPrivatePtr priv = (SynapticsPrivatePtr) (local->private);
+
+ ErrorF("Synaptics DeviceOn called\n");
+
+ local->fd = xf86OpenSerial(local->options);
+ if (local->fd == -1) {
+ xf86Msg(X_WARNING, "%s: cannot open input device\n", local->name);
+ return (!Success);
+ }
+
+ priv->buffer = XisbNew(local->fd, 64);
+ if (!priv->buffer) {
+ xf86CloseSerial(local->fd);
+ local->fd = -1;
+ return (!Success);
+ }
+
+ xf86FlushInput(local->fd);
+ xf86AddEnabledDevice (local);
+ dev->public.on = TRUE;
+ return (Success);
+}
+
+static Bool
+DeviceOff(DeviceIntPtr dev)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ SynapticsPrivatePtr priv = (SynapticsPrivatePtr) (local->private);
+
+ ErrorF("Synaptics DeviceOff called\n");
+
+ if (local->fd != -1) {
+ xf86RemoveEnabledDevice (local);
+ if (priv->buffer) {
+ XisbFree(priv->buffer);
+ priv->buffer = NULL;
+ }
+ xf86CloseSerial(local->fd);
+ }
+
+ RemoveEnabledDevice (local->fd);
+ dev->public.on = FALSE;
+ return (Success);
+}
+
+static Bool
+DeviceInit(DeviceIntPtr dev)
+{
+ LocalDevicePtr local = (LocalDevicePtr) dev->public.devicePrivate;
+ unsigned char map[] = {0, 1, 2, 3, 4, 5};
+
+ ErrorF("Synaptics DeviceInit called\n");
+
+ dev->public.on = FALSE;
+
+ InitPointerDeviceStruct((DevicePtr)dev, map,
+ 5,
+ miPointerGetMotionEvents, SynapticsCtrl,
+ miPointerGetMotionBufferSize());
+
+ /* X valuator */
+ xf86InitValuatorAxisStruct(dev, 0, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(dev, 0);
+ /* Y valuator */
+ xf86InitValuatorAxisStruct(dev, 1, 0, -1, 1, 0, 1);
+ xf86InitValuatorDefaults(dev, 1);
+
+ xf86MotionHistoryAllocate(local);
+
+ return Success;
+}
+
+static int
+move_distance(int dx, int dy) {
+ return(xf86sqrt((dx * dx) + (dy * dy)));
+}
+
+static edge_type
+edge_detection( SynapticsPrivatePtr priv, int x, int y ) {
+
+ edge_type edge = 0;
+
+ if(x > priv->synpara->right_edge)
+ edge |= RIGHT_EDGE;
+ else if(x < priv->synpara->left_edge)
+ edge |= LEFT_EDGE;
+
+ if(y > priv->synpara->top_edge)
+ edge |= TOP_EDGE;
+ else if(y < priv->synpara->bottom_edge)
+ edge |= BOTTOM_EDGE;
+
+ return( edge );
+}
+
+static CARD32
+updownTimer(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+ LocalDevicePtr local = (LocalDevicePtr) (arg);
+ SynapticsPrivatePtr priv = (SynapticsPrivatePtr) (local->private);
+ int sigstate, change, id;
+
+ sigstate = xf86BlockSIGIO ();
+
+ change = priv->repeatButtons;
+ while(change) {
+ id = ffs(change);
+ change &= ~(1 << (id - 1));
+ xf86PostButtonEvent(local->dev, FALSE, id, FALSE, 0, 0);
+ xf86PostButtonEvent(local->dev, FALSE, id, TRUE, 0, 0);
+ }
+
+ xf86UnblockSIGIO (sigstate);
+
+ priv->repeat_timer = TimerSet(priv->repeat_timer, 0, 100, updownTimer, local);
+
+ return 0;
+}
+
+
+#define MOVE_HIST(a) ((priv->count_packet_finger-(a))%SYNAPTICS_MOVE_HISTORY)
+
+static void
+ReadInput(LocalDevicePtr local)
+{
+ SynapticsPrivatePtr priv = (SynapticsPrivatePtr) (local->private);
+ SynapticsSHMPtr para = priv->synpara;
+ Bool finger;
+ int x, y, z, w, dist, dx, dy, buttons, id;
+ edge_type edge;
+ Bool left, mid, right, up, down;
+ double speed, integral;
+ int change;
+
+ /*
+ * set blocking to -1 on the first call because we know there is data to
+ * read. Xisb automatically clears it after one successful read so that
+ * succeeding reads are preceeded buy a select with a 0 timeout to prevent
+ * read from blocking indefinately.
+ */
+ XisbBlockDuration(priv->buffer, -1);
+ while(SynapticsGetPacket(local, priv) == Success)
+ {
+ /* process input data */
+ x = ((priv->protoBuf[3] & 0x10) << 8) |
+ ((priv->protoBuf[1] & 0x0f) << 8) |
+ priv->protoBuf[4];
+ y = ((priv->protoBuf[3] & 0x20) << 7) |
+ ((priv->protoBuf[1] & 0xf0) << 4) |
+ priv->protoBuf[5];
+ /* pressure */
+ z = priv->protoBuf[2];
+ w = ((priv->protoBuf[0] & 0x30) >> 2) |
+ ((priv->protoBuf[0] & 0x04) >> 1) |
+ ((priv->protoBuf[3] & 0x04) >> 2);
+
+ left = (priv->protoBuf[0] & 0x01) ? TRUE : FALSE;
+ mid = FALSE;
+ right = (priv->protoBuf[0] & 0x2) ? TRUE : FALSE;
+ up = ((priv->protoBuf[3] & 0x01) && !left) ? TRUE : FALSE;
+ down = ((priv->protoBuf[3] & 0x02) && !right) ? TRUE : FALSE;
+
+ edge = edge_detection(priv, x, y);
+
+ dx = dy = 0;
+
+ /* shared memory */
+ para->x = x;
+ para->y = y;
+
+ /* 3rd button emulation */
+ if(!left && !right) {
+ priv->count_button_delay = priv->count_packet;
+ priv->third_button = FALSE;
+ } else if(DIFF_TIME(priv->count_packet, priv->count_button_delay) < 6) {
+ left = right = FALSE;
+ } else if(DIFF_TIME(priv->count_packet, priv->count_button_delay) == 6) {
+ priv->third_button = left && right;
+ }
+ if(priv->third_button) {
+ mid = TRUE;
+ left = right = FALSE;
+ }
+
+ /* finger detection thru pressure an threshold */
+ finger = (((z > para->finger_high) && !priv->finger_flag) ||
+ ((z > para->finger_low) && priv->finger_flag));
+
+ /* tap and drag detection */
+ if(finger && !priv->finger_flag) { /* touched */
+ DBG(7, ErrorF("touched - x:%d, y:%d packet:%lu\n", x, y, priv->count_packet));
+ if(priv->tap) {
+ DBG(7, ErrorF("drag detected - tap time:%lu\n", priv->count_packet_tapping));
+ priv->drag = TRUE; /* drag gesture */
+ }
+ priv->touch_on.x = x;
+ priv->touch_on.y = y;
+ priv->touch_on.packet = priv->count_packet;
+ } else if(!finger && priv->finger_flag) { /* untouched */
+ DBG(7, ErrorF("untouched - x:%d, y:%d packet:%lu finger:%d\n",
+ x, y, priv->count_packet, priv->finger_count));
+ /* check if
+ 1. the tap is in tap_time
+ 2. the max movement is in tap_move or more than one finger are tapped */
+ if((DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time) &&
+ (((abs(x - priv->touch_on.x) < para->tap_move) &&
+ (abs(y - priv->touch_on.y) < para->tap_move)) ||
+ priv->finger_count)) {
+ if(priv->drag) {
+ DBG(7, ErrorF("double tapping detected\n"));
+ priv->doubletap = TRUE;
+ priv->tap = FALSE;
+ } else {
+ DBG(7, ErrorF("tapping detected @ "));
+ priv->count_packet_tapping = priv->count_packet;
+ priv->tap = TRUE;
+ if(priv->finger_count == 0) {
+ switch(edge) {
+ case RIGHT_TOP_EDGE:
+ DBG(7, ErrorF("right top edge\n"));
+ priv->tap_mid = TRUE;
+ break;
+ case RIGHT_BOTTOM_EDGE:
+ DBG(7, ErrorF("right bottom edge\n"));
+ priv->tap_right = TRUE;
+ break;
+ case LEFT_TOP_EDGE:
+ DBG(7, ErrorF("left top edge\n"));
+ break;
+ case LEFT_BOTTOM_EDGE:
+ DBG(7, ErrorF("left bottom edge\n"));
+ break;
+ default:
+ DBG(7, ErrorF("no edge\n"));
+ priv->tap_left = TRUE;
+ }
+ } else {
+ switch(priv->finger_count) {
+ case 2:
+ DBG(7, ErrorF("two finger tap\n"));
+ priv->tap_mid = TRUE;
+ break;
+ case 3:
+ DBG(7, ErrorF("three finger tap\n"));
+ priv->tap_right = TRUE;
+ break;
+ default:
+ DBG(7, ErrorF("one finger\n"));
+ priv->tap_left = TRUE;
+ }
+ }
+ }
+ } /* tap detection */
+ priv->drag = FALSE;
+ } /* finger lost */
+
+ /* detecting 2 and 3 fingers */
+ if(finger && (DIFF_TIME(priv->count_packet, priv->touch_on.packet) < para->tap_time)) {
+ if((w == 0) && (priv->finger_count == 0))
+ priv->finger_count = 2;
+ if(w == 1)
+ priv->finger_count = 3;
+ } else
+ priv->finger_count = 0;
+
+ /* reset tapping button flags */
+ if(!priv->tap && !priv->drag && !priv->doubletap) {
+ priv->tap_left = priv->tap_mid = priv->tap_right = FALSE;
+ }
+
+ /* tap processing */
+ if(priv->tap &&
+ (DIFF_TIME(priv->count_packet, priv->count_packet_tapping) < para->tap_time)) {
+ left = priv->tap_left;
+ mid = priv->tap_mid;
+ right = priv->tap_right;
+ } else {
+ priv->tap = FALSE;
+ }
+
+ /* drag processing */
+ if(priv->drag) {
+ left = priv->tap_left;
+ mid = priv->tap_mid;
+ right = priv->tap_right;
+ }
+
+ /* double tap processing */
+ if(priv->doubletap && !priv->finger_flag) {
+ left = priv->tap_left;
+ mid = priv->tap_mid;
+ right = priv->tap_right;
+ priv->doubletap = FALSE;
+ }
+
+ /* scroll detection */
+ if(finger && !priv->finger_flag) {
+ if(edge & RIGHT_EDGE) {
+ priv->vert_scroll_on = TRUE;
+ priv->scroll_y = y;
+ DBG(7, ErrorF("edge scroll detected on right edge\n"));
+ }
+ }
+ if(priv->vert_scroll_on && (!(edge & RIGHT_EDGE) || !finger)) {
+ DBG(7, ErrorF("edge scroll off\n"));
+ priv->vert_scroll_on = FALSE;
+ }
+
+ /* scroll processing */
+ if(priv->vert_scroll_on) {
+ dist = y - priv->scroll_y; /* + = up, - = down */
+ if(dist > para->scroll_dist_vert) {
+ up = TRUE;
+ priv->scroll_y += para->scroll_dist_vert;
+ }
+ else if(dist < (-1 * para->scroll_dist_vert)) {
+ down = TRUE;
+ priv->scroll_y -= para->scroll_dist_vert;
+ }
+ }
+
+ /* movement */
+ if(finger && !priv->vert_scroll_on && !priv->finger_count) {
+ if(priv->count_packet_finger > 3) { /* min. 3 packets */
+ dy = (1 *
+ (((priv->move_hist[MOVE_HIST(1)].y + priv->move_hist[MOVE_HIST(2)].y) / 2) -
+ ((y + priv->move_hist[MOVE_HIST(1)].y) / 2)));
+ dx = (-1 *
+ (((priv->move_hist[MOVE_HIST(1)].x + priv->move_hist[MOVE_HIST(2)].x) / 2) -
+ ((x + priv->move_hist[MOVE_HIST(1)].x) / 2)));
+
+ /* speed in depence of distance/packet */
+ dist = move_distance( dx, dy );
+ speed = dist * para->accl;
+ if(speed > para->max_speed)
+ speed = para->max_speed;
+ else if(speed < para->min_speed)
+ speed = para->min_speed;
+
+ /* save the fraction for adding to the next priv->count_packet */
+ priv->frac_x = xf86modf((dx * speed) + priv->frac_x, &integral);
+ dx = integral;
+ priv->frac_y = xf86modf((dy * speed) + priv->frac_y, &integral);
+ dy = integral;
+ }
+
+ priv->count_packet_finger++;
+ } else {
+ priv->count_packet_finger = 0;
+ }
+
+
+ buttons = ((left ? 0x01 : 0) |
+ (mid ? 0x02 : 0) |
+ (right ? 0x04 : 0) |
+ (up ? 0x08 : 0) |
+ (down ? 0x10 : 0));
+
+ priv->count_packet++;
+
+ /* Flags */
+ priv->finger_flag = finger;
+ priv->move_hist[MOVE_HIST(0)].y = y;
+ priv->move_hist[MOVE_HIST(0)].x = x;
+
+ /* repeat timer for up/down buttons */
+ /* when you press a button the packets will only send for a second, so
+ we have to use a timer for repeating */
+ if((up || down) && !priv->vert_scroll_on) {
+ if(!priv->repeat_timer) {
+ priv->repeatButtons = buttons & 0x18;
+ priv->repeat_timer = TimerSet(priv->repeat_timer,
+ 0, 200, updownTimer, local);
+ }
+ } else if(priv->repeat_timer) {
+ TimerFree(priv->repeat_timer);
+ priv->repeat_timer = NULL;
+ priv->repeatButtons = 0;
+ }
+
+ /* Post events */
+ if(dx || dy)
+ xf86PostMotionEvent(local->dev, 0, 0, 2, dx, dy);
+
+ change = buttons ^ priv->lastButtons;
+ while(change) {
+ id = ffs(change);
+ change &= ~(1 << (id - 1));
+ xf86PostButtonEvent(local->dev, FALSE, id, (buttons & (1 << (id - 1))), 0, 0);
+ }
+ priv->lastButtons = buttons;
+ }
+}
+
+static int
+ControlProc(LocalDevicePtr local, xDeviceCtl * control)
+{
+ ErrorF("Control Proc called\n");
+ return (Success);
+}
+
+static void
+CloseProc (LocalDevicePtr local)
+{
+ ErrorF("Close Proc called\n");
+}
+
+static int
+SwitchMode (ClientPtr client, DeviceIntPtr dev, int mode)
+{
+ ErrorF("SwitchMode called\n");
+ return (Success);
+}
+
+static Bool
+ConvertProc (LocalDevicePtr local,
+ int first,
+ int num,
+ int v0,
+ int v1,
+ int v2,
+ int v3,
+ int v4,
+ int v5,
+ int *x,
+ int *y)
+{
+ if(first != 0 || num != 2)
+ return FALSE;
+
+ *x = v0;
+ *y = v1;
+
+ return TRUE;
+}
+
+
+static Bool
+QueryHardware (LocalDevicePtr local)
+{
+ SynapticsPrivatePtr priv = (SynapticsPrivatePtr) local->private;
+ SynapticsSHMPtr para = priv->synpara;
+ int retries;
+
+ xf86Msg(X_INFO, "synaptics touchpad driver %s\n", VERSION);
+
+ /* is the synaptics touchpad active? */
+ priv->isSynaptics = QueryIsSynaptics(local->fd);
+
+ if((!priv->isSynaptics) && (!para->repeater || (priv->fifofd == -1))) {
+ xf86Msg(X_ERROR, "%s no synaptics touchpad detected and no repeater device\n",
+ local->name);
+ priv->isSynaptics = TRUE;
+ return(!Success);
+ }
+
+ if(!priv->isSynaptics) {
+ xf86Msg(X_PROBED, "%s no synaptics touchpad, data piped to repeater fifo\n", local->name);
+ synaptics_reset(local->fd);
+ SynapticsEnableDevice(local->fd);
+ return(Success);
+ }
+
+ xf86Msg(X_PROBED, "%s synaptics touchpad found\n", local->name);
+
+ retries = 3;
+ while((retries++ <= 3) && (synaptics_reset(local->fd) != Success))
+ xf86Msg(X_ERROR, "%s reset failed\n", local->name);
+
+ if(synaptics_identify(local->fd, &priv->identity) != Success)
+ return !Success;
+
+ if(synaptics_model_id(local->fd, &priv->model_id) != Success)
+ return !Success;
+
+ if(synaptics_capability(local->fd, &priv->capabilities) != Success)
+ return !Success;
+
+ if(synaptics_set_mode(local->fd, SYN_BIT_ABSOLUTE_MODE |
+ SYN_BIT_HIGH_RATE |
+ SYN_BIT_DISABLE_GESTURE |
+ SYN_BIT_W_MODE) != Success)
+ return !Success;
+
+ PrintIdent(priv);
+ return Success;
+}
+
+static Bool
+SynapticsGetPacket(LocalDevicePtr local, SynapticsPrivatePtr priv)
+{
+ int count = 0;
+ int c;
+ unsigned char *pBuf, u;
+
+ pBuf = priv->protoBuf;
+
+ while((c = XisbRead(priv->buffer)) >= 0) {
+ u = (unsigned char)c;
+
+ /* test if there is a reset sequence received */
+ if((c == 0x00) && (priv->lastByte == 0xAA)) {
+ if(xf86WaitForInput(local->fd, 50000) == 0 ) {
+ DBG(7, ErrorF("Reset received\n"));
+ QueryHardware(local);
+ } else
+ ErrorF("faked reset received\n");
+ }
+ priv->lastByte = u;
+
+ /* when there is no synaptics touchpad pipe the data to the repeater fifo */
+ if(!priv->isSynaptics) {
+ xf86write(priv->fifofd, &u, 1);
+ if(++count >= 3)
+ return(!Success);
+ continue;
+ }
+
+ /* to avoid endless loops */
+ if(count++ > 100) {
+ return (!Success);
+ }
+
+ pBuf[priv->protoBufTail++] = u;
+
+ /* check first byte */
+ if((priv->protoBufTail == 1) && ((u & 0xC8) != 0x80)) {
+ priv->inSync = FALSE;
+ priv->protoBufTail = 0;
+ DBG(4, ErrorF("Synaptics driver lost sync at 1st byte\n"));
+ continue;
+ }
+
+ /* check 4th byte */
+ if((priv->protoBufTail == 4) && ((u & 0xc8) != 0xc0)) {
+ priv->inSync = FALSE;
+ priv->protoBufTail = 0;
+ DBG(4, ErrorF("Synaptics driver lost sync at 4th byte\n"));
+ continue;
+ }
+
+ if(priv->protoBufTail >= 6) { /* Full packet received */
+ if(!priv->inSync) {
+ priv->inSync = TRUE;
+ DBG(4, ErrorF("Synaptics driver resynced.\n"));
+ }
+ priv->protoBufTail = 0;
+ return Success;
+ }
+ }
+
+ return !Success;
+}
+
+static void
+PrintIdent(SynapticsPrivatePtr priv) {
+
+ xf86Msg(X_PROBED, " Synaptics Touchpad, model: %d\n", SYN_ID_MODEL(priv->identity));
+ xf86Msg(X_PROBED, " Firware: %d.%d\n", SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity));
+
+ if(SYN_MODEL_ROT180(priv->model_id))
+ xf86Msg(X_PROBED, " 180 degree mounted touchpad\n");
+ if(SYN_MODEL_PORTRAIT(priv->model_id))
+ xf86Msg(X_PROBED, " portrait touchpad\n");
+ xf86Msg(X_PROBED, " Sensor: %d\n", SYN_MODEL_SENSOR(priv->model_id));
+ if(SYN_MODEL_NEWABS(priv->model_id))
+ xf86Msg(X_PROBED, " new absolute packet format\n");
+ if(SYN_MODEL_PEN(priv->model_id))
+ xf86Msg(X_PROBED, " pen detection\n");
+
+ if(SYN_CAP_EXTENDED(priv->capabilities)) {
+ xf86Msg(X_PROBED, " Touchpad has extended capabiliety bits\n");
+ if(SYN_CAP_FOUR_BUTTON(priv->capabilities))
+ xf86Msg(X_PROBED, " -> four buttons\n");
+ if(SYN_CAP_MULTIFINGER(priv->capabilities))
+ xf86Msg(X_PROBED, " -> multifinger detection\n");
+ if(SYN_CAP_PALMDETECT(priv->capabilities))
+ xf86Msg(X_PROBED, " -> palm detection\n");
+ }
+}
+
+/* vim:ts=2:sw=2:cindent:
+*/