From 5b12f7b4d8993eb16342e33c98f533a5344c1abd Mon Sep 17 00:00:00 2001 From: Matthieu Herrb Date: Sat, 12 Jul 2014 15:43:55 +0200 Subject: OpenBSD wsconscomm support from shadchin@ --- Makefile.am | 2 +- configure.ac | 8 ++ man/Makefile.am | 1 - src/Makefile.am | 5 + src/synaptics.c | 3 + src/synproto.h | 3 + src/wsconscomm.c | 318 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 src/wsconscomm.c diff --git a/Makefile.am b/Makefile.am index 521188e..632e23f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ --with-sdkdir='$${includedir}/xorg' \ --with-xorg-conf-dir='$${datadir}/X11/xorg.conf.d' -SUBDIRS = include src man tools conf +SUBDIRS = include src man tools MAINTAINERCLEANFILES = ChangeLog INSTALL pkgconfigdir = $(libdir)/pkgconfig diff --git a/configure.ac b/configure.ac index 1a96457..bd64c2a 100644 --- a/configure.ac +++ b/configure.ac @@ -115,6 +115,10 @@ case "${host}" in AC_MSG_RESULT([ps2comm alpscomm]) BUILD_PS2COMM="yes" ;; +*openbsd*) + AC_MSG_RESULT([wsconscomm]) + BUILD_WSCONSCOMM="yes" + ;; *) AC_MSG_ERROR([Cannot find suitable backends for this platform.]) ;; @@ -136,9 +140,13 @@ fi if test "x$BUILD_PS2COMM" = xyes; then AC_DEFINE(BUILD_PS2COMM, 1, [Optional backend ps2comm and alpscomm enabled]) fi +if test "x$BUILD_WSCONSCOMM" = xyes; then + AC_DEFINE(BUILD_WSCONSCOMM, 1, [Optional backend wsconscomm enabled]) +fi AM_CONDITIONAL([BUILD_EVENTCOMM], [test "x${BUILD_EVENTCOMM}" = "xyes"]) AM_CONDITIONAL([BUILD_PSMCOMM], [test "x${BUILD_PSMCOMM}" = "xyes"]) AM_CONDITIONAL([BUILD_PS2COMM], [test "x${BUILD_PS2COMM}" = "xyes"]) +AM_CONDITIONAL([BUILD_WSCONSCOMM], [test "x${BUILD_WSCONSCOMM}" = "xyes"]) # ----------------------------------------------------------------------------- # Dependencies for synclient and syndaemon diff --git a/man/Makefile.am b/man/Makefile.am index 24420eb..380a437 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -1,4 +1,3 @@ -# $Id$ # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # diff --git a/src/Makefile.am b/src/Makefile.am index 6ac254b..6ab6c33 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,3 +56,8 @@ if BUILD_PSMCOMM synaptics_drv_la_SOURCES += \ psmcomm.c endif + +if BUILD_WSCONSCOMM +synaptics_drv_la_SOURCES += \ + wsconscomm.c +endif diff --git a/src/synaptics.c b/src/synaptics.c index 02adc0d..fcc3c20 100644 --- a/src/synaptics.c +++ b/src/synaptics.c @@ -148,6 +148,9 @@ static const struct { #ifdef BUILD_PS2COMM { "psaux", &psaux_proto_operations }, { "alps", &alps_proto_operations }, +#endif +#ifdef BUILD_WSCONSCOMM + { "wscons", &wscons_proto_operations }, #endif { NULL, NULL } }; diff --git a/src/synproto.h b/src/synproto.h index 6ba6740..a40d56b 100644 --- a/src/synproto.h +++ b/src/synproto.h @@ -121,6 +121,9 @@ extern struct SynapticsProtocolOperations event_proto_operations; #ifdef BUILD_PSMCOMM extern struct SynapticsProtocolOperations psm_proto_operations; #endif /* BUILD_PSMCOMM */ +#ifdef BUILD_WSCONSCOMM +extern struct SynapticsProtocolOperations wscons_proto_operations; +#endif /* BUILD_WSCONSCOMM */ extern struct SynapticsHwState *SynapticsHwStateAlloc(SynapticsPrivate * priv); extern void SynapticsHwStateFree(struct SynapticsHwState **hw); diff --git a/src/wsconscomm.c b/src/wsconscomm.c new file mode 100644 index 0000000..0e0c81d --- /dev/null +++ b/src/wsconscomm.c @@ -0,0 +1,318 @@ +/* + * Copyright © 2011 Alexandr Shadchin + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include "synproto.h" +#include "synapticsstr.h" +#include + +#include +#include + +#ifdef X_PRIVSEP +extern int priv_open_device(const char *); +#endif + +#define DEFAULT_WSMOUSE_DEV "/dev/wsmouse0" + +static Bool +WSConsIsTouchpad(InputInfoPtr pInfo, const char *device) +{ + int wsmouse_type, fd = -1; + Bool rc = FALSE; + + if (device) { +#ifndef X_PRIVSEP + fd = open(device, O_RDWR); +#else + fd = priv_open_device(device); +#endif + } else + fd = pInfo->fd; + + if (fd < 0) + return FALSE; + + if (ioctl(fd, WSMOUSEIO_GTYPE, &wsmouse_type) == -1) { + xf86IDrvMsg(pInfo, X_ERROR, "cannot get mouse type\n"); + goto out; + } + + if (wsmouse_type == WSMOUSE_TYPE_SYNAPTICS || + wsmouse_type == WSMOUSE_TYPE_ALPS || + wsmouse_type == WSMOUSE_TYPE_ELANTECH) + rc = TRUE; + +out: + if (device) + close(fd); + + return rc; +} + +static Bool +WSConsReadEvent(InputInfoPtr pInfo, struct wscons_event *event) +{ + Bool rc = TRUE; + ssize_t len; + + len = read(pInfo->fd, event, sizeof(struct wscons_event)); + if (len <= 0) { + if (errno != EAGAIN) + xf86IDrvMsg(pInfo, X_ERROR, "read error %s\n", strerror(errno)); + rc = FALSE; + } else if (len % sizeof(struct wscons_event)) { + xf86IDrvMsg(pInfo, X_ERROR, "read error, invalid number of bytes\n"); + rc = FALSE; + } + + return rc; +} + +static Bool +WSConsDeviceOnHook(InputInfoPtr pInfo, SynapticsParameters *para) +{ + int wsmouse_mode = WSMOUSE_NATIVE; + + if (ioctl(pInfo->fd, WSMOUSEIO_SETMODE, &wsmouse_mode) == -1) { + xf86IDrvMsg(pInfo, X_ERROR, "cannot set native mode\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +WSConsDeviceOffHook(InputInfoPtr pInfo) +{ + int wsmouse_mode = WSMOUSE_COMPAT; + + if (ioctl(pInfo->fd, WSMOUSEIO_SETMODE, &wsmouse_mode) == -1) { + xf86IDrvMsg(pInfo, X_ERROR, "cannot set compat mode\n"); + return FALSE; + } + + return TRUE; +} + +static Bool +WSConsQueryHardware(InputInfoPtr pInfo) +{ + return WSConsIsTouchpad(pInfo, NULL); +} + +static Bool +WSConsReadHwState(InputInfoPtr pInfo, + struct CommData *comm, struct SynapticsHwState *hwRet) +{ + SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private; + struct SynapticsHwState *hw = comm->hwState; + struct wscons_event event; + Bool v; + + /* Reset cumulative values if buttons were not previously pressed */ + if (!hw->left && !hw->right && !hw->middle) { + hw->cumulative_dx = hw->x; + hw->cumulative_dy = hw->y; + } + + while (WSConsReadEvent(pInfo, &event)) { + switch (event.type) { + case WSCONS_EVENT_MOUSE_UP: + case WSCONS_EVENT_MOUSE_DOWN: + v = (event.type == WSCONS_EVENT_MOUSE_DOWN) ? TRUE : FALSE; + switch (event.value) { + case 0: + hw->left = v; + break; + case 1: + hw->middle = v; + break; + case 2: + hw->right = v; + break; + case 3: + hw->up = v; + break; + case 4: + hw->down = v; + break; + case 5: + hw->multi[0] = v; + break; + case 6: + hw->multi[1] = v; + break; + case 7: + hw->multi[2] = v; + break; + case 8: + hw->multi[3] = v; + break; + case 9: + hw->multi[4] = v; + break; + case 10: + hw->multi[5] = v; + break; + case 11: + hw->multi[6] = v; + break; + case 12: + hw->multi[7] = v; + break; + } + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_X: + hw->x = event.value; + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_Y: + hw->y = priv->maxy - event.value + priv->miny; + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_Z: + hw->z = event.value; + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_W: + if (priv->model == MODEL_ELANTECH) { + /* Elantech touchpads report number of fingers directly. */ + hw->fingerWidth = 5; + hw->numFingers = event.value; + break; + } + /* XXX magic number mapping which is mirrored in pms driver */ + switch (event.value) { + case 0: + hw->fingerWidth = 5; + hw->numFingers = 2; + break; + case 1: + hw->fingerWidth = 5; + hw->numFingers = 3; + break; + case 4 ... 5: + hw->fingerWidth = event.value; + hw->numFingers = 1; + break; + } + break; + case WSCONS_EVENT_SYNC: + hw->millis = 1000 * event.time.tv_sec + event.time.tv_nsec / 1000000; + SynapticsCopyHwState(hwRet, hw); + return TRUE; + default: + return FALSE; + } + } + + return FALSE; +} + +static Bool +WSConsAutoDevProbe(InputInfoPtr pInfo, const char *device) +{ + int i; + + if (device && WSConsIsTouchpad(pInfo, device)) + return TRUE; + + if (WSConsIsTouchpad(pInfo, DEFAULT_WSMOUSE_DEV)) { + xf86IDrvMsg(pInfo, X_PROBED, "auto-dev sets device to %s\n", + DEFAULT_WSMOUSE_DEV); + xf86ReplaceStrOption(pInfo->options, "Device", DEFAULT_WSMOUSE_DEV); + return TRUE; + } + + return FALSE; +} + +static void +WSConsReadDevDimensions(InputInfoPtr pInfo) +{ + SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private; + struct wsmouse_calibcoords wsmc; + int wsmouse_type; + + if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS, &wsmc) != 0) { + xf86IDrvMsg(pInfo, X_ERROR, "failed to query axis range (%s)\n", + strerror(errno)); + return; + } + + priv->minx = wsmc.minx; + priv->maxx = wsmc.maxx; + priv->resx = wsmc.resx; + xf86IDrvMsg(pInfo, X_PROBED, "x-axis range %d - %d resolution %d\n", + priv->minx, priv->maxx, priv->resx); + + priv->miny = wsmc.miny; + priv->maxy = wsmc.maxy; + priv->resy = wsmc.resy; + xf86IDrvMsg(pInfo, X_PROBED, "y-axis range %d - %d resolution %d\n", + priv->miny, priv->maxy, priv->resy); + + priv->minp = 0; + priv->maxp = 255; + + priv->minw = 0; + priv->maxw = 15; + + priv->has_pressure = TRUE; + priv->has_left = TRUE; + priv->has_right = TRUE; + priv->has_middle = TRUE; + + if (ioctl(pInfo->fd, WSMOUSEIO_GTYPE, &wsmouse_type) == -1) + xf86IDrvMsg(pInfo, X_ERROR, "cannot get mouse type\n"); + + switch (wsmouse_type) { + default: + case WSMOUSE_TYPE_SYNAPTICS: + priv->model = MODEL_SYNAPTICS; + priv->has_width = TRUE; + priv->has_double = TRUE; + priv->has_triple = TRUE; + break; + case WSMOUSE_TYPE_ALPS: + priv->model = MODEL_ALPS; + priv->has_width = FALSE; + priv->has_double = FALSE; + priv->has_triple = FALSE; + break; + case WSMOUSE_TYPE_ELANTECH: + priv->model = MODEL_ELANTECH; + priv->has_width = TRUE; + priv->has_double = TRUE; + priv->has_triple = TRUE; + break; + } +} + +struct SynapticsProtocolOperations wscons_proto_operations = { + WSConsDeviceOnHook, + WSConsDeviceOffHook, + WSConsQueryHardware, + WSConsReadHwState, + WSConsAutoDevProbe, + WSConsReadDevDimensions +}; -- cgit v1.2.3