Edit

IABSD.fr/xenocara/driver/xf86-input-synaptics/src/wsconscomm.c

Branch :

  • Show log

    Commit

  • Author : jcs
    Date : 2018-07-30 16:00:39
    Hash : 65b51547
    Message : setup WSMOUSE_TYPE_TOUCHPAD devices to use ws driver by default, but allow them to work with xf86-input-synaptics with and ok bru@

  • driver/xf86-input-synaptics/src/wsconscomm.c
  • /*
     * 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 <xorg-server.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <sys/time.h>
    #include <errno.h>
    #include <string.h>
    #include "synproto.h"
    #include "synapticsstr.h"
    #include <xf86.h>
    
    #include <fcntl.h>
    #include <dev/wscons/wsconsio.h>
    
    #ifdef X_PRIVSEP
    extern int priv_open_device(const char *);
    #endif
    
    #define DEFAULT_WSMOUSE_DEV		"/dev/wsmouse0"
    
    #define NWSEVENTS	16
    
    struct wsconscomm_proto_data {
        struct wscons_event	events[NWSEVENTS];
        size_t		events_count;
        size_t		events_pos;
    };
    
    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_SYNAP_SBTN ||
            wsmouse_type == WSMOUSE_TYPE_ALPS ||
            wsmouse_type == WSMOUSE_TYPE_ELANTECH ||
            wsmouse_type == WSMOUSE_TYPE_TOUCHPAD)
            rc = TRUE;
    
    out:
        if (device)
            close(fd);
    
        return rc;
    }
    
    static size_t
    WSConsReadEvents(InputInfoPtr pInfo)
    {
        SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
        struct wsconscomm_proto_data *proto_data = priv->proto_data;
        ssize_t len;
    
        proto_data->events_count = proto_data->events_pos = 0;
        len = read(pInfo->fd, proto_data->events, sizeof(proto_data->events));
        if (len <= 0) {
            if (errno != EAGAIN)
                xf86IDrvMsg(pInfo, X_ERROR, "read error %s\n", strerror(errno));
        } else if (len % sizeof(struct wscons_event)) {
            xf86IDrvMsg(pInfo, X_ERROR, "read error, invalid number of bytes\n");
        } else {
            proto_data->events_count = len / sizeof(struct wscons_event);
        }
    
        return proto_data->events_count;
    }
    
    static struct wscons_event *
    WSConsGetEvent(InputInfoPtr pInfo)
    {
        SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
        struct wsconscomm_proto_data *proto_data = priv->proto_data;
        struct wscons_event *event;
    
        if (proto_data->events_count == 0 && WSConsReadEvents(pInfo) == 0)
            return NULL;
    
        event = &proto_data->events[proto_data->events_pos];
        proto_data->events_pos++;
        proto_data->events_count--;
    
        return event;
    }
    
    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 void
    WSConsAdjustScrollCoords(SynapticsPrivate *priv, struct SynapticsHwState *hw)
    {
        int dx, dy, i;
    
        dx = hw->x - priv->scroll.last_x;
        dy = hw->y - priv->scroll.last_y;
        priv->scroll.last_x = hw->x;
        priv->scroll.last_y = hw->y;
        for (i = 0; i < SYNAPTICS_MOVE_HISTORY; i++) {
            priv->move_hist[i].x += dx;
            priv->move_hist[i].y += dy;
        }
    }
    
    static Bool
    WSConsReadHwState(InputInfoPtr pInfo,
        struct CommData *comm, struct SynapticsHwState *hwRet)
    {
        SynapticsPrivate *priv = (SynapticsPrivate *)pInfo->private;
        struct wsconscomm_proto_data *proto_data = priv->proto_data;
        struct SynapticsHwState *hw = comm->hwState;
        struct wscons_event *event;
        Bool v, reset = FALSE;
    
        while ((event = WSConsGetEvent(pInfo)) != NULL) {
            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;
                hw->cumulative_dx = hw->x;
                break;
            case WSCONS_EVENT_MOUSE_ABSOLUTE_Y:
                hw->y = priv->maxy - event->value + priv->miny;
                hw->cumulative_dy = hw->y;
                break;
            case WSCONS_EVENT_TOUCH_PRESSURE:
                hw->z = event->value;
                break;
            case WSCONS_EVENT_TOUCH_CONTACTS:
                hw->numFingers = event->value;
                if (hw->numFingers == 0)
                    hw->fingerWidth = 0;
                else if (hw->fingerWidth == 0)
                    hw->fingerWidth = 5;
                break;
            case WSCONS_EVENT_TOUCH_WIDTH:
                hw->fingerWidth = event->value;
                break;
            case WSCONS_EVENT_TOUCH_RESET:
                /* The contact count or the active MT slot has changed. */
                reset = TRUE;
                break;
            case WSCONS_EVENT_SYNC:
                if (reset) {
                    /* Ensure that pointer motion stops. */
                    priv->count_packet_finger = 0;
                    /* Don't use stale coordinates for filtering. */
                    priv->hyst_center_x = hw->x;
                    priv->hyst_center_y = hw->y;
                    if (priv->vert_scroll_twofinger_on
                        || priv->horiz_scroll_twofinger_on) {
                        WSConsAdjustScrollCoords(priv, hw);
                    }
                }
                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;
        SynapticsParameters *para = &priv->synpara;
        struct wsmouse_calibcoords wsmc;
        int wsmouse_type;
    
        priv->proto_data = calloc(1, sizeof(struct wsconscomm_proto_data));
        if (priv->proto_data == NULL) {
            xf86IDrvMsg(pInfo, X_ERROR, "failed to allocate protocol data (%s)\n",
                strerror(errno));
            return;
        }
    
        if (ioctl(pInfo->fd, WSMOUSEIO_GCALIBCOORDS, &wsmc) != 0) {
            free(priv->proto_data);
            priv->proto_data = NULL;
            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_SYNAP_SBTN:
            para->clickpad = TRUE;
            para->has_secondary_buttons = TRUE;
            /* FALLTHROUGH */
        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_TOUCHPAD:
        	/* Use Elantech settings for the generic type. */
    	/* FALLTHROUGH */
        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
    };