105b261ecSmrg/*
205b261ecSmrg * Copyright 1995-1999 by Frederic Lepied, France. <Lepied@XFree86.org>
335c4bbdfSmrg *
405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
505b261ecSmrg * documentation for any purpose is  hereby granted without fee, provided that
605b261ecSmrg * the  above copyright   notice appear  in   all  copies and  that both  that
705b261ecSmrg * copyright  notice   and   this  permission   notice  appear  in  supporting
805b261ecSmrg * documentation, and that   the  name of  Frederic   Lepied not  be  used  in
905b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1005b261ecSmrg * specific,  written      prior  permission.     Frederic  Lepied   makes  no
1105b261ecSmrg * representations about the suitability of this software for any purpose.  It
1235c4bbdfSmrg * is provided "as is" without express or implied warranty.
1335c4bbdfSmrg *
1405b261ecSmrg * FREDERIC  LEPIED DISCLAIMS ALL   WARRANTIES WITH REGARD  TO  THIS SOFTWARE,
1505b261ecSmrg * INCLUDING ALL IMPLIED   WARRANTIES OF MERCHANTABILITY  AND   FITNESS, IN NO
1605b261ecSmrg * EVENT  SHALL FREDERIC  LEPIED BE   LIABLE   FOR ANY  SPECIAL, INDIRECT   OR
1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1805b261ecSmrg * DATA  OR PROFITS, WHETHER  IN  AN ACTION OF  CONTRACT,  NEGLIGENCE OR OTHER
1905b261ecSmrg * TORTIOUS  ACTION, ARISING    OUT OF OR   IN  CONNECTION  WITH THE USE    OR
2005b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2105b261ecSmrg *
2205b261ecSmrg */
2305b261ecSmrg/*
2405b261ecSmrg * Copyright (c) 2000-2002 by The XFree86 Project, Inc.
2505b261ecSmrg *
2605b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
2705b261ecSmrg * copy of this software and associated documentation files (the "Software"),
2805b261ecSmrg * to deal in the Software without restriction, including without limitation
2905b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
3005b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
3105b261ecSmrg * Software is furnished to do so, subject to the following conditions:
3205b261ecSmrg *
3305b261ecSmrg * The above copyright notice and this permission notice shall be included in
3405b261ecSmrg * all copies or substantial portions of the Software.
3505b261ecSmrg *
3605b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3705b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3805b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
3905b261ecSmrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
4005b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
4105b261ecSmrg * OTHER DEALINGS IN THE SOFTWARE.
4205b261ecSmrg *
4305b261ecSmrg * Except as contained in this notice, the name of the copyright holder(s)
4405b261ecSmrg * and author(s) shall not be used in advertising or otherwise to promote
4505b261ecSmrg * the sale, use or other dealings in this Software without prior written
4605b261ecSmrg * authorization from the copyright holder(s) and author(s).
4705b261ecSmrg */
4805b261ecSmrg
4905b261ecSmrg#ifdef HAVE_XORG_CONFIG_H
5005b261ecSmrg#include <xorg-config.h>
5105b261ecSmrg#endif
5205b261ecSmrg
5305b261ecSmrg#include <X11/Xfuncproto.h>
5405b261ecSmrg#include <X11/Xmd.h>
5505b261ecSmrg#include <X11/extensions/XI.h>
5605b261ecSmrg#include <X11/extensions/XIproto.h>
576747b715Smrg#include <X11/Xatom.h>
5805b261ecSmrg#include "xf86.h"
5905b261ecSmrg#include "xf86Priv.h"
606747b715Smrg#include "xf86Config.h"
6105b261ecSmrg#include "xf86Xinput.h"
6205b261ecSmrg#include "xf86Optrec.h"
6305b261ecSmrg#include "mipointer.h"
644642e01fSmrg#include "extinit.h"
656747b715Smrg#include "loaderProcs.h"
6635c4bbdfSmrg#include "systemd-logind.h"
6705b261ecSmrg
6835c4bbdfSmrg#include "exevents.h"           /* AddInputDevice */
6905b261ecSmrg#include "exglobals.h"
706747b715Smrg#include "eventstr.h"
719ace9065Smrg#include "inpututils.h"
7235c4bbdfSmrg#include "optionstr.h"
736747b715Smrg
7435c4bbdfSmrg#include <string.h>             /* InputClassMatches */
756747b715Smrg#ifdef HAVE_FNMATCH_H
766747b715Smrg#include <fnmatch.h>
776747b715Smrg#endif
786747b715Smrg#ifdef HAVE_SYS_UTSNAME_H
796747b715Smrg#include <sys/utsname.h>
806747b715Smrg#endif
8105b261ecSmrg
8205b261ecSmrg#include <stdarg.h>
8335c4bbdfSmrg#include <stdint.h>             /* for int64_t */
8435c4bbdfSmrg#include <sys/types.h>
8535c4bbdfSmrg#include <sys/stat.h>
8635c4bbdfSmrg#include <unistd.h>
871b5d61b8Smrg#ifdef HAVE_SYS_SYSMACROS_H
881b5d61b8Smrg#include <sys/sysmacros.h>
891b5d61b8Smrg#endif
9035c4bbdfSmrg#ifdef HAVE_SYS_MKDEV_H
9135c4bbdfSmrg#include <sys/mkdev.h>          /* for major() & minor() on Solaris */
9235c4bbdfSmrg#endif
9305b261ecSmrg
9405b261ecSmrg#include "mi.h"
9505b261ecSmrg
9635c4bbdfSmrg#include <ptrveloc.h>           /* dix pointer acceleration */
976747b715Smrg#include <xserver-properties.h>
984642e01fSmrg
9905b261ecSmrg#ifdef XFreeXDGA
10005b261ecSmrg#include "dgaproc.h"
10105b261ecSmrg#endif
10205b261ecSmrg
1034642e01fSmrg#include "xkbsrv.h"
1044642e01fSmrg
1059ace9065Smrg/* Valuator verification macro */
1069ace9065Smrg#define XI_VERIFY_VALUATORS(num_valuators)					\
1079ace9065Smrg	if (num_valuators > MAX_VALUATORS) {					\
1089ace9065Smrg		xf86Msg(X_ERROR, "%s: num_valuator %d is greater than"		\
1099ace9065Smrg			" MAX_VALUATORS\n", __FUNCTION__, num_valuators);	\
1109ace9065Smrg		return;								\
1119ace9065Smrg	}
1124642e01fSmrg
1139ace9065Smrgstatic int
11435c4bbdfSmrg xf86InputDevicePostInit(DeviceIntPtr dev);
11535c4bbdfSmrg
1161b5d61b8Smrgtypedef struct {
1171b5d61b8Smrg    struct xorg_list node;
1181b5d61b8Smrg    InputInfoPtr pInfo;
1191b5d61b8Smrg} PausedInputDeviceRec;
1201b5d61b8Smrgtypedef PausedInputDeviceRec *PausedInputDevicePtr;
1211b5d61b8Smrg
1221b5d61b8Smrgstatic struct xorg_list new_input_devices_list = {
1231b5d61b8Smrg    .next = &new_input_devices_list,
1241b5d61b8Smrg    .prev = &new_input_devices_list,
1251b5d61b8Smrg};
1269ace9065Smrg
1274642e01fSmrg/**
1284642e01fSmrg * Eval config and modify DeviceVelocityRec accordingly
1294642e01fSmrg */
1304642e01fSmrgstatic void
13135c4bbdfSmrgProcessVelocityConfiguration(DeviceIntPtr pDev, const char *devname, void *list,
1326747b715Smrg                             DeviceVelocityPtr s)
1336747b715Smrg{
1346747b715Smrg    int tempi;
1356747b715Smrg    float tempf;
1366747b715Smrg    Atom float_prop = XIGetKnownProperty(XATOM_FLOAT);
1376747b715Smrg    Atom prop;
1384642e01fSmrg
13935c4bbdfSmrg    if (!s)
1404642e01fSmrg        return;
1414642e01fSmrg
1426747b715Smrg    /* common settings (available via device properties) */
1434642e01fSmrg    tempf = xf86SetRealOption(list, "ConstantDeceleration", 1.0);
1441b5d61b8Smrg    if (tempf != 1.0) {
1454642e01fSmrg        xf86Msg(X_CONFIG, "%s: (accel) constant deceleration by %.1f\n",
1464642e01fSmrg                devname, tempf);
1476747b715Smrg        prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
1486747b715Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
1496747b715Smrg                               PropModeReplace, 1, &tempf, FALSE);
1504642e01fSmrg    }
1514642e01fSmrg
1524642e01fSmrg    tempf = xf86SetRealOption(list, "AdaptiveDeceleration", 1.0);
1536747b715Smrg    if (tempf > 1.0) {
1544642e01fSmrg        xf86Msg(X_CONFIG, "%s: (accel) adaptive deceleration by %.1f\n",
1554642e01fSmrg                devname, tempf);
1566747b715Smrg        prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
1576747b715Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
1586747b715Smrg                               PropModeReplace, 1, &tempf, FALSE);
1596747b715Smrg    }
1606747b715Smrg
1616747b715Smrg    /* select profile by number */
1626747b715Smrg    tempi = xf86SetIntOption(list, "AccelerationProfile",
16335c4bbdfSmrg                             s->statistics.profile_number);
1646747b715Smrg
1656747b715Smrg    prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
1666747b715Smrg    if (XIChangeDeviceProperty(pDev, prop, XA_INTEGER, 32,
1676747b715Smrg                               PropModeReplace, 1, &tempi, FALSE) == Success) {
1686747b715Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i\n", devname,
1696747b715Smrg                tempi);
17035c4bbdfSmrg    }
17135c4bbdfSmrg    else {
1726747b715Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i is unknown\n",
1736747b715Smrg                devname, tempi);
1746747b715Smrg    }
1756747b715Smrg
1766747b715Smrg    /* set scaling */
1776747b715Smrg    tempf = xf86SetRealOption(list, "ExpectedRate", 0);
1786747b715Smrg    prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
1796747b715Smrg    if (tempf > 0) {
1806747b715Smrg        tempf = 1000.0 / tempf;
1816747b715Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
1826747b715Smrg                               PropModeReplace, 1, &tempf, FALSE);
18335c4bbdfSmrg    }
18435c4bbdfSmrg    else {
1856747b715Smrg        tempf = xf86SetRealOption(list, "VelocityScale", s->corr_mul);
1866747b715Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
1876747b715Smrg                               PropModeReplace, 1, &tempf, FALSE);
1884642e01fSmrg    }
1894642e01fSmrg
1906747b715Smrg    tempi = xf86SetIntOption(list, "VelocityTrackerCount", -1);
1916747b715Smrg    if (tempi > 1)
19235c4bbdfSmrg        InitTrackers(s, tempi);
1936747b715Smrg
1946747b715Smrg    s->initial_range = xf86SetIntOption(list, "VelocityInitialRange",
1956747b715Smrg                                        s->initial_range);
1966747b715Smrg
1976747b715Smrg    s->max_diff = xf86SetRealOption(list, "VelocityAbsDiff", s->max_diff);
1986747b715Smrg
1996747b715Smrg    tempf = xf86SetRealOption(list, "VelocityRelDiff", -1);
2006747b715Smrg    if (tempf >= 0) {
20135c4bbdfSmrg        xf86Msg(X_CONFIG, "%s: (accel) max rel. velocity difference: %.1f%%\n",
20235c4bbdfSmrg                devname, tempf * 100.0);
20335c4bbdfSmrg        s->max_rel_diff = tempf;
2044642e01fSmrg    }
2054642e01fSmrg
2064642e01fSmrg    /*  Configure softening. If const deceleration is used, this is expected
2074642e01fSmrg     *  to provide better subpixel information so we enable
2084642e01fSmrg     *  softening by default only if ConstantDeceleration is not used
2094642e01fSmrg     */
2104642e01fSmrg    s->use_softening = xf86SetBoolOption(list, "Softening",
2114642e01fSmrg                                         s->const_acceleration == 1.0);
2124642e01fSmrg
2134642e01fSmrg    s->average_accel = xf86SetBoolOption(list, "AccelerationProfileAveraging",
2144642e01fSmrg                                         s->average_accel);
2154642e01fSmrg
2164642e01fSmrg    s->reset_time = xf86SetIntOption(list, "VelocityReset", s->reset_time);
2174642e01fSmrg}
2184642e01fSmrg
2194642e01fSmrgstatic void
22035c4bbdfSmrgApplyAccelerationSettings(DeviceIntPtr dev)
22135c4bbdfSmrg{
2226747b715Smrg    int scheme, i;
2234642e01fSmrg    DeviceVelocityPtr pVel;
22435c4bbdfSmrg    InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
22535c4bbdfSmrg    char *schemeStr;
2264642e01fSmrg
2276747b715Smrg    if (dev->valuator && dev->ptrfeed) {
22835c4bbdfSmrg        schemeStr = xf86SetStrOption(pInfo->options, "AccelerationScheme", "");
2294642e01fSmrg
23035c4bbdfSmrg        scheme = dev->valuator->accelScheme.number;
2314642e01fSmrg
23235c4bbdfSmrg        if (!xf86NameCmp(schemeStr, "predictable"))
23335c4bbdfSmrg            scheme = PtrAccelPredictable;
2344642e01fSmrg
23535c4bbdfSmrg        if (!xf86NameCmp(schemeStr, "lightweight"))
23635c4bbdfSmrg            scheme = PtrAccelLightweight;
2374642e01fSmrg
23835c4bbdfSmrg        if (!xf86NameCmp(schemeStr, "none"))
23935c4bbdfSmrg            scheme = PtrAccelNoOp;
2404642e01fSmrg
2414642e01fSmrg        /* reinit scheme if needed */
2426747b715Smrg        if (dev->valuator->accelScheme.number != scheme) {
2436747b715Smrg            if (dev->valuator->accelScheme.AccelCleanupProc) {
2444642e01fSmrg                dev->valuator->accelScheme.AccelCleanupProc(dev);
2454642e01fSmrg            }
2464642e01fSmrg
2476747b715Smrg            if (InitPointerAccelerationScheme(dev, scheme)) {
24835c4bbdfSmrg                xf86Msg(X_CONFIG, "%s: (accel) selected scheme %s/%i\n",
24935c4bbdfSmrg                        pInfo->name, schemeStr, scheme);
25035c4bbdfSmrg            }
25135c4bbdfSmrg            else {
25235c4bbdfSmrg                xf86Msg(X_CONFIG, "%s: (accel) could not init scheme %s\n",
25335c4bbdfSmrg                        pInfo->name, schemeStr);
25435c4bbdfSmrg                scheme = dev->valuator->accelScheme.number;
2554642e01fSmrg            }
25635c4bbdfSmrg        }
25735c4bbdfSmrg        else {
2584642e01fSmrg            xf86Msg(X_CONFIG, "%s: (accel) keeping acceleration scheme %i\n",
2599ace9065Smrg                    pInfo->name, scheme);
2604642e01fSmrg        }
2614642e01fSmrg
2626747b715Smrg        free(schemeStr);
2634642e01fSmrg
2644642e01fSmrg        /* process special configuration */
2656747b715Smrg        switch (scheme) {
26635c4bbdfSmrg        case PtrAccelPredictable:
26735c4bbdfSmrg            pVel = GetDevicePredictableAccelData(dev);
26835c4bbdfSmrg            ProcessVelocityConfiguration(dev, pInfo->name, pInfo->options,
26935c4bbdfSmrg                                         pVel);
27035c4bbdfSmrg            break;
2714642e01fSmrg        }
2726747b715Smrg
2739ace9065Smrg        i = xf86SetIntOption(pInfo->options, "AccelerationNumerator",
2746747b715Smrg                             dev->ptrfeed->ctrl.num);
2756747b715Smrg        if (i >= 0)
2766747b715Smrg            dev->ptrfeed->ctrl.num = i;
2776747b715Smrg
2789ace9065Smrg        i = xf86SetIntOption(pInfo->options, "AccelerationDenominator",
2796747b715Smrg                             dev->ptrfeed->ctrl.den);
2806747b715Smrg        if (i > 0)
2816747b715Smrg            dev->ptrfeed->ctrl.den = i;
2826747b715Smrg
2839ace9065Smrg        i = xf86SetIntOption(pInfo->options, "AccelerationThreshold",
2846747b715Smrg                             dev->ptrfeed->ctrl.threshold);
2856747b715Smrg        if (i >= 0)
2866747b715Smrg            dev->ptrfeed->ctrl.threshold = i;
2876747b715Smrg
2886747b715Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration factor: %.3f\n",
28935c4bbdfSmrg                pInfo->name, ((float) dev->ptrfeed->ctrl.num) /
29035c4bbdfSmrg                ((float) dev->ptrfeed->ctrl.den));
2916747b715Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration threshold: %i\n",
2929ace9065Smrg                pInfo->name, dev->ptrfeed->ctrl.threshold);
2934642e01fSmrg    }
2944642e01fSmrg}
29505b261ecSmrg
29635c4bbdfSmrgstatic void
29735c4bbdfSmrgApplyTransformationMatrix(DeviceIntPtr dev)
29835c4bbdfSmrg{
29935c4bbdfSmrg    InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
30035c4bbdfSmrg    char *str;
30135c4bbdfSmrg    int rc;
30235c4bbdfSmrg    float matrix[9] = { 0 };
30335c4bbdfSmrg
30435c4bbdfSmrg    if (!dev->valuator)
30535c4bbdfSmrg        return;
30635c4bbdfSmrg
30735c4bbdfSmrg    str = xf86SetStrOption(pInfo->options, "TransformationMatrix", NULL);
30835c4bbdfSmrg    if (!str)
30935c4bbdfSmrg        return;
31035c4bbdfSmrg
31135c4bbdfSmrg    rc = sscanf(str, "%f %f %f %f %f %f %f %f %f", &matrix[0], &matrix[1],
31235c4bbdfSmrg                &matrix[2], &matrix[3], &matrix[4], &matrix[5], &matrix[6],
31335c4bbdfSmrg                &matrix[7], &matrix[8]);
31435c4bbdfSmrg    if (rc != 9) {
31535c4bbdfSmrg        xf86Msg(X_ERROR,
31635c4bbdfSmrg                "%s: invalid format for transformation matrix. Ignoring configuration.\n",
31735c4bbdfSmrg                pInfo->name);
31835c4bbdfSmrg        return;
31935c4bbdfSmrg    }
32035c4bbdfSmrg
32135c4bbdfSmrg    XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM),
32235c4bbdfSmrg                           XIGetKnownProperty(XATOM_FLOAT), 32,
32335c4bbdfSmrg                           PropModeReplace, 9, matrix, FALSE);
32435c4bbdfSmrg}
32535c4bbdfSmrg
326ed6184dfSmrgstatic void
327ed6184dfSmrgApplyAutoRepeat(DeviceIntPtr dev)
328ed6184dfSmrg{
329ed6184dfSmrg    InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
330ed6184dfSmrg    XkbSrvInfoPtr xkbi;
331ed6184dfSmrg    char *repeatStr;
332ed6184dfSmrg    long delay, rate;
333ed6184dfSmrg
334ed6184dfSmrg    if (!dev->key)
335ed6184dfSmrg        return;
336ed6184dfSmrg
337ed6184dfSmrg    xkbi = dev->key->xkbInfo;
338ed6184dfSmrg
339ed6184dfSmrg    repeatStr = xf86SetStrOption(pInfo->options, "AutoRepeat", NULL);
340ed6184dfSmrg    if (!repeatStr)
341ed6184dfSmrg        return;
342ed6184dfSmrg
343ed6184dfSmrg    if (sscanf(repeatStr, "%ld %ld", &delay, &rate) != 2) {
344ed6184dfSmrg        xf86Msg(X_ERROR, "\"%s\" is not a valid AutoRepeat value\n", repeatStr);
345ed6184dfSmrg        return;
346ed6184dfSmrg    }
347ed6184dfSmrg
348ed6184dfSmrg    xf86Msg(X_CONFIG, "AutoRepeat: %ld %ld\n", delay, rate);
349ed6184dfSmrg    xkbi->desc->ctrls->repeat_delay = delay;
350ed6184dfSmrg    xkbi->desc->ctrls->repeat_interval = rate;
351ed6184dfSmrg}
352ed6184dfSmrg
35305b261ecSmrg/***********************************************************************
35405b261ecSmrg *
35505b261ecSmrg * xf86ProcessCommonOptions --
35635c4bbdfSmrg *
35705b261ecSmrg *	Process global options.
35805b261ecSmrg *
35905b261ecSmrg ***********************************************************************
36005b261ecSmrg */
3616747b715Smrgvoid
36235c4bbdfSmrgxf86ProcessCommonOptions(InputInfoPtr pInfo, XF86OptionPtr list)
36305b261ecSmrg{
3649ace9065Smrg    if (xf86SetBoolOption(list, "Floating", 0) ||
3659ace9065Smrg        !xf86SetBoolOption(list, "AlwaysCore", 1) ||
36605b261ecSmrg        !xf86SetBoolOption(list, "SendCoreEvents", 1) ||
36705b261ecSmrg        !xf86SetBoolOption(list, "CorePointer", 1) ||
36805b261ecSmrg        !xf86SetBoolOption(list, "CoreKeyboard", 1)) {
3699ace9065Smrg        xf86Msg(X_CONFIG, "%s: doesn't report core events\n", pInfo->name);
37035c4bbdfSmrg    }
37135c4bbdfSmrg    else {
3729ace9065Smrg        pInfo->flags |= XI86_ALWAYS_CORE;
3739ace9065Smrg        xf86Msg(X_CONFIG, "%s: always reports core events\n", pInfo->name);
37405b261ecSmrg    }
37505b261ecSmrg}
37605b261ecSmrg
37705b261ecSmrg/***********************************************************************
37805b261ecSmrg *
37905b261ecSmrg * xf86ActivateDevice --
3804642e01fSmrg *
38105b261ecSmrg *	Initialize an input device.
38205b261ecSmrg *
3834642e01fSmrg * Returns TRUE on success, or FALSE otherwise.
38405b261ecSmrg ***********************************************************************
38505b261ecSmrg */
3869ace9065Smrgstatic DeviceIntPtr
3879ace9065Smrgxf86ActivateDevice(InputInfoPtr pInfo)
38805b261ecSmrg{
38935c4bbdfSmrg    DeviceIntPtr dev;
39035c4bbdfSmrg    Atom atom;
39105b261ecSmrg
3929ace9065Smrg    dev = AddInputDevice(serverClient, pInfo->device_control, TRUE);
3934642e01fSmrg
39435c4bbdfSmrg    if (dev == NULL) {
39535c4bbdfSmrg        xf86Msg(X_ERROR, "Too many input devices. Ignoring %s\n", pInfo->name);
3969ace9065Smrg        pInfo->dev = NULL;
3979ace9065Smrg        return NULL;
39805b261ecSmrg    }
3994642e01fSmrg
4009ace9065Smrg    atom = MakeAtom(pInfo->type_name, strlen(pInfo->type_name), TRUE);
4019ace9065Smrg    AssignTypeAndName(dev, atom, pInfo->name);
4029ace9065Smrg    dev->public.devicePrivate = pInfo;
4039ace9065Smrg    pInfo->dev = dev;
40405b261ecSmrg
4059ace9065Smrg    dev->coreEvents = pInfo->flags & XI86_ALWAYS_CORE;
4069ace9065Smrg    dev->type = SLAVE;
4079ace9065Smrg    dev->spriteInfo->spriteOwner = FALSE;
40805b261ecSmrg
4099ace9065Smrg    dev->config_info = xf86SetStrOption(pInfo->options, "config_info", NULL);
41005b261ecSmrg
4119ace9065Smrg    if (serverGeneration == 1)
41235c4bbdfSmrg        xf86Msg(X_INFO,
41335c4bbdfSmrg                "XINPUT: Adding extended input device \"%s\" (type: %s, id %d)\n",
41435c4bbdfSmrg                pInfo->name, pInfo->type_name, dev->id);
41505b261ecSmrg
4169ace9065Smrg    return dev;
41705b261ecSmrg}
41805b261ecSmrg
41905b261ecSmrg/****************************************************************************
42005b261ecSmrg *
42105b261ecSmrg * Caller:	ProcXSetDeviceMode
42205b261ecSmrg *
42305b261ecSmrg * Change the mode of an extension device.
42405b261ecSmrg * This function is used to change the mode of a device from reporting
42505b261ecSmrg * relative motion to reporting absolute positional information, and
42605b261ecSmrg * vice versa.
42705b261ecSmrg * The default implementation below is that no such devices are supported.
42805b261ecSmrg *
42905b261ecSmrg ***********************************************************************
43005b261ecSmrg */
43105b261ecSmrg
43205b261ecSmrgint
43335c4bbdfSmrgSetDeviceMode(ClientPtr client, DeviceIntPtr dev, int mode)
43405b261ecSmrg{
43535c4bbdfSmrg    InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
43605b261ecSmrg
43735c4bbdfSmrg    if (pInfo->switch_mode) {
43835c4bbdfSmrg        return (*pInfo->switch_mode) (client, dev, mode);
43935c4bbdfSmrg    }
44035c4bbdfSmrg    else
44135c4bbdfSmrg        return BadMatch;
44205b261ecSmrg}
44305b261ecSmrg
44405b261ecSmrg/***********************************************************************
44505b261ecSmrg *
44605b261ecSmrg * Caller:	ProcXSetDeviceValuators
44705b261ecSmrg *
44805b261ecSmrg * Set the value of valuators on an extension input device.
44905b261ecSmrg * This function is used to set the initial value of valuators on
45005b261ecSmrg * those input devices that are capable of reporting either relative
45105b261ecSmrg * motion or an absolute position, and allow an initial position to be set.
45205b261ecSmrg * The default implementation below is that no such devices are supported.
45305b261ecSmrg *
45405b261ecSmrg ***********************************************************************
45505b261ecSmrg */
45605b261ecSmrg
45705b261ecSmrgint
45835c4bbdfSmrgSetDeviceValuators(ClientPtr client, DeviceIntPtr dev, int *valuators,
45935c4bbdfSmrg                   int first_valuator, int num_valuators)
46005b261ecSmrg{
4619ace9065Smrg    InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
46205b261ecSmrg
4639ace9065Smrg    if (pInfo->set_device_valuators)
46435c4bbdfSmrg        return (*pInfo->set_device_valuators) (pInfo, valuators, first_valuator,
46535c4bbdfSmrg                                               num_valuators);
46605b261ecSmrg
46705b261ecSmrg    return BadMatch;
46805b261ecSmrg}
46905b261ecSmrg
47005b261ecSmrg/***********************************************************************
47105b261ecSmrg *
47205b261ecSmrg * Caller:	ProcXChangeDeviceControl
47305b261ecSmrg *
47405b261ecSmrg * Change the specified device controls on an extension input device.
47505b261ecSmrg *
47605b261ecSmrg ***********************************************************************
47705b261ecSmrg */
47805b261ecSmrg
47905b261ecSmrgint
48035c4bbdfSmrgChangeDeviceControl(ClientPtr client, DeviceIntPtr dev, xDeviceCtl * control)
48105b261ecSmrg{
48235c4bbdfSmrg    InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
48335c4bbdfSmrg
48435c4bbdfSmrg    if (!pInfo->control_proc) {
48535c4bbdfSmrg        switch (control->control) {
48635c4bbdfSmrg        case DEVICE_CORE:
48735c4bbdfSmrg        case DEVICE_ABS_CALIB:
48835c4bbdfSmrg        case DEVICE_ABS_AREA:
48935c4bbdfSmrg            return BadMatch;
49035c4bbdfSmrg        case DEVICE_RESOLUTION:
49135c4bbdfSmrg        case DEVICE_ENABLE:
49235c4bbdfSmrg            return Success;
49335c4bbdfSmrg        default:
49435c4bbdfSmrg            return BadMatch;
49535c4bbdfSmrg        }
49635c4bbdfSmrg    }
49735c4bbdfSmrg    else {
49835c4bbdfSmrg        return (*pInfo->control_proc) (pInfo, control);
49935c4bbdfSmrg    }
50005b261ecSmrg}
50105b261ecSmrg
5026747b715Smrg/*
5036747b715Smrg * Get the operating system name from uname and store it statically to avoid
5046747b715Smrg * repeating the system call each time MatchOS is checked.
5056747b715Smrg */
5066747b715Smrgstatic const char *
5076747b715SmrgHostOS(void)
5086747b715Smrg{
5096747b715Smrg#ifdef HAVE_SYS_UTSNAME_H
5106747b715Smrg    struct utsname name;
5116747b715Smrg    static char host_os[sizeof(name.sysname)] = "";
5126747b715Smrg
5136747b715Smrg    if (*host_os == '\0') {
5146747b715Smrg        if (uname(&name) >= 0)
51535c4bbdfSmrg            strlcpy(host_os, name.sysname, sizeof(host_os));
5166747b715Smrg        else {
51735c4bbdfSmrg            strlcpy(host_os, "unknown", sizeof(host_os));
5186747b715Smrg        }
5196747b715Smrg    }
5206747b715Smrg    return host_os;
5216747b715Smrg#else
5226747b715Smrg    return "";
5236747b715Smrg#endif
5246747b715Smrg}
5256747b715Smrg
5266747b715Smrgstatic int
5276747b715Smrgmatch_substring(const char *attr, const char *pattern)
5286747b715Smrg{
5296747b715Smrg    return (strstr(attr, pattern)) ? 0 : -1;
5306747b715Smrg}
5316747b715Smrg
5326747b715Smrg#ifdef HAVE_FNMATCH_H
5336747b715Smrgstatic int
5346747b715Smrgmatch_pattern(const char *attr, const char *pattern)
53505b261ecSmrg{
5366747b715Smrg    return fnmatch(pattern, attr, 0);
5376747b715Smrg}
5386747b715Smrg#else
5396747b715Smrg#define match_pattern match_substring
5406747b715Smrg#endif
5416747b715Smrg
5426747b715Smrg#ifdef HAVE_FNMATCH_H
5436747b715Smrgstatic int
5446747b715Smrgmatch_path_pattern(const char *attr, const char *pattern)
5456747b715Smrg{
5466747b715Smrg    return fnmatch(pattern, attr, FNM_PATHNAME);
5476747b715Smrg}
5486747b715Smrg#else
5496747b715Smrg#define match_path_pattern match_substring
5506747b715Smrg#endif
5516747b715Smrg
55235c4bbdfSmrg/*
55335c4bbdfSmrg * If no Layout section is found, xf86ServerLayout.id becomes "(implicit)"
55435c4bbdfSmrg * It is convenient that "" in patterns means "no explicit layout"
55535c4bbdfSmrg */
55635c4bbdfSmrgstatic int
55735c4bbdfSmrgmatch_string_implicit(const char *attr, const char *pattern)
55835c4bbdfSmrg{
55935c4bbdfSmrg    if (strlen(pattern)) {
56035c4bbdfSmrg        return strcmp(attr, pattern);
56135c4bbdfSmrg    }
56235c4bbdfSmrg    else {
56335c4bbdfSmrg        return strcmp(attr, "(implicit)");
56435c4bbdfSmrg    }
56535c4bbdfSmrg}
56635c4bbdfSmrg
5676747b715Smrg/*
5686747b715Smrg * Match an attribute against a list of NULL terminated arrays of patterns.
5696747b715Smrg * If a pattern in each list entry is matched, return TRUE.
5706747b715Smrg */
5716747b715Smrgstatic Bool
57235c4bbdfSmrgMatchAttrToken(const char *attr, struct xorg_list *patterns,
57335c4bbdfSmrg               int (*compare) (const char *attr, const char *pattern))
5746747b715Smrg{
5756747b715Smrg    const xf86MatchGroup *group;
5766747b715Smrg
5776747b715Smrg    /* If there are no patterns, accept the match */
57835c4bbdfSmrg    if (xorg_list_is_empty(patterns))
5796747b715Smrg        return TRUE;
5806747b715Smrg
5816747b715Smrg    /*
5821b5d61b8Smrg     * Iterate the list of patterns ensuring each entry has a
5836747b715Smrg     * match. Each list entry is a separate Match line of the same type.
5846747b715Smrg     */
58535c4bbdfSmrg    xorg_list_for_each_entry(group, patterns, entry) {
58635c4bbdfSmrg        char *const *cur;
5871b5d61b8Smrg        Bool is_negated = group->is_negated;
5881b5d61b8Smrg        Bool match = is_negated;
5891b5d61b8Smrg
5901b5d61b8Smrg        /* If there's a pattern but no attribute, we reject the match for a
5911b5d61b8Smrg         * MatchFoo directive, and accept it for a NoMatchFoo directive
5921b5d61b8Smrg         */
5931b5d61b8Smrg        if (!attr)
5941b5d61b8Smrg            return is_negated;
5956747b715Smrg
5966747b715Smrg        for (cur = group->values; *cur; cur++)
59735c4bbdfSmrg            if ((*compare) (attr, *cur) == 0) {
5981b5d61b8Smrg                match = !is_negated;
5996747b715Smrg                break;
6006747b715Smrg            }
6016747b715Smrg        if (!match)
6026747b715Smrg            return FALSE;
6036747b715Smrg    }
6046747b715Smrg
6056747b715Smrg    /* All the entries in the list matched the attribute */
6066747b715Smrg    return TRUE;
6076747b715Smrg}
6086747b715Smrg
6096747b715Smrg/*
6106747b715Smrg * Classes without any Match statements match all devices. Otherwise, all
6116747b715Smrg * statements must match.
6126747b715Smrg */
6136747b715Smrgstatic Bool
6149ace9065SmrgInputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
61535c4bbdfSmrg                  const InputAttributes * attrs)
6166747b715Smrg{
6176747b715Smrg    /* MatchProduct substring */
61835c4bbdfSmrg    if (!MatchAttrToken
61935c4bbdfSmrg        (attrs->product, &iclass->match_product, match_substring))
6206747b715Smrg        return FALSE;
6216747b715Smrg
6226747b715Smrg    /* MatchVendor substring */
6236747b715Smrg    if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
6246747b715Smrg        return FALSE;
6256747b715Smrg
6266747b715Smrg    /* MatchDevicePath pattern */
62735c4bbdfSmrg    if (!MatchAttrToken
62835c4bbdfSmrg        (attrs->device, &iclass->match_device, match_path_pattern))
6296747b715Smrg        return FALSE;
6306747b715Smrg
6316747b715Smrg    /* MatchOS case-insensitive string */
6326747b715Smrg    if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
6336747b715Smrg        return FALSE;
6346747b715Smrg
6356747b715Smrg    /* MatchPnPID pattern */
6366747b715Smrg    if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
6376747b715Smrg        return FALSE;
6386747b715Smrg
6396747b715Smrg    /* MatchUSBID pattern */
6406747b715Smrg    if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
6416747b715Smrg        return FALSE;
6426747b715Smrg
6436747b715Smrg    /* MatchDriver string */
6446747b715Smrg    if (!MatchAttrToken(idev->driver, &iclass->match_driver, strcmp))
6456747b715Smrg        return FALSE;
6466747b715Smrg
6476747b715Smrg    /*
6486747b715Smrg     * MatchTag string
6496747b715Smrg     * See if any of the device's tags match any of the MatchTag tokens.
6506747b715Smrg     */
65135c4bbdfSmrg    if (!xorg_list_is_empty(&iclass->match_tag)) {
65235c4bbdfSmrg        char *const *tag;
6536747b715Smrg        Bool match;
6546747b715Smrg
6556747b715Smrg        if (!attrs->tags)
6566747b715Smrg            return FALSE;
6576747b715Smrg        for (tag = attrs->tags, match = FALSE; *tag; tag++) {
6586747b715Smrg            if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
6596747b715Smrg                match = TRUE;
6606747b715Smrg                break;
6616747b715Smrg            }
6626747b715Smrg        }
6636747b715Smrg        if (!match)
6646747b715Smrg            return FALSE;
6656747b715Smrg    }
6666747b715Smrg
66735c4bbdfSmrg    /* MatchLayout string */
66835c4bbdfSmrg    if (!xorg_list_is_empty(&iclass->match_layout)) {
66935c4bbdfSmrg        if (!MatchAttrToken(xf86ConfigLayout.id,
67035c4bbdfSmrg                            &iclass->match_layout, match_string_implicit))
67135c4bbdfSmrg            return FALSE;
67235c4bbdfSmrg    }
67335c4bbdfSmrg
6746747b715Smrg    /* MatchIs* booleans */
6756747b715Smrg    if (iclass->is_keyboard.set &&
6761b5d61b8Smrg        iclass->is_keyboard.val != ! !(attrs->flags & (ATTR_KEY|ATTR_KEYBOARD)))
6776747b715Smrg        return FALSE;
6786747b715Smrg    if (iclass->is_pointer.set &&
67935c4bbdfSmrg        iclass->is_pointer.val != ! !(attrs->flags & ATTR_POINTER))
6806747b715Smrg        return FALSE;
6816747b715Smrg    if (iclass->is_joystick.set &&
68235c4bbdfSmrg        iclass->is_joystick.val != ! !(attrs->flags & ATTR_JOYSTICK))
6836747b715Smrg        return FALSE;
6846747b715Smrg    if (iclass->is_tablet.set &&
68535c4bbdfSmrg        iclass->is_tablet.val != ! !(attrs->flags & ATTR_TABLET))
6866747b715Smrg        return FALSE;
6871b5d61b8Smrg    if (iclass->is_tablet_pad.set &&
6881b5d61b8Smrg        iclass->is_tablet_pad.val != ! !(attrs->flags & ATTR_TABLET_PAD))
6891b5d61b8Smrg        return FALSE;
6906747b715Smrg    if (iclass->is_touchpad.set &&
69135c4bbdfSmrg        iclass->is_touchpad.val != ! !(attrs->flags & ATTR_TOUCHPAD))
6926747b715Smrg        return FALSE;
6936747b715Smrg    if (iclass->is_touchscreen.set &&
69435c4bbdfSmrg        iclass->is_touchscreen.val != ! !(attrs->flags & ATTR_TOUCHSCREEN))
6956747b715Smrg        return FALSE;
6966747b715Smrg
6976747b715Smrg    return TRUE;
6986747b715Smrg}
6996747b715Smrg
7006747b715Smrg/*
7016747b715Smrg * Merge in any InputClass configurations. Options in each InputClass
7026747b715Smrg * section have more priority than the original device configuration as
7036747b715Smrg * well as any previous InputClass sections.
7046747b715Smrg */
7056747b715Smrgstatic int
70635c4bbdfSmrgMergeInputClasses(const InputInfoPtr idev, const InputAttributes * attrs)
7076747b715Smrg{
7086747b715Smrg    XF86ConfInputClassPtr cl;
7096747b715Smrg    XF86OptionPtr classopts;
7106747b715Smrg
7116747b715Smrg    for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
7126747b715Smrg        if (!InputClassMatches(cl, idev, attrs))
7136747b715Smrg            continue;
7146747b715Smrg
7156747b715Smrg        /* Collect class options and driver settings */
7166747b715Smrg        classopts = xf86optionListDup(cl->option_lst);
7176747b715Smrg        if (cl->driver) {
71835c4bbdfSmrg            free((void *) idev->driver);
7196747b715Smrg            idev->driver = xstrdup(cl->driver);
7206747b715Smrg            if (!idev->driver) {
7216747b715Smrg                xf86Msg(X_ERROR, "Failed to allocate memory while merging "
7226747b715Smrg                        "InputClass configuration");
7236747b715Smrg                return BadAlloc;
7246747b715Smrg            }
72535c4bbdfSmrg            classopts = xf86ReplaceStrOption(classopts, "driver", idev->driver);
7266747b715Smrg        }
7276747b715Smrg
7286747b715Smrg        /* Apply options to device with InputClass settings preferred. */
7296747b715Smrg        xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n",
7309ace9065Smrg                idev->name, cl->identifier);
7319ace9065Smrg        idev->options = xf86optionListMerge(idev->options, classopts);
7326747b715Smrg    }
7336747b715Smrg
7346747b715Smrg    return Success;
7356747b715Smrg}
7366747b715Smrg
7376747b715Smrg/*
7386747b715Smrg * Iterate the list of classes and look for Option "Ignore". Return the
7396747b715Smrg * value of the last matching class and holler when returning TRUE.
7406747b715Smrg */
7416747b715Smrgstatic Bool
74235c4bbdfSmrgIgnoreInputClass(const InputInfoPtr idev, const InputAttributes * attrs)
7436747b715Smrg{
7446747b715Smrg    XF86ConfInputClassPtr cl;
7456747b715Smrg    Bool ignore = FALSE;
7466747b715Smrg    const char *ignore_class;
7476747b715Smrg
7486747b715Smrg    for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
7496747b715Smrg        if (!InputClassMatches(cl, idev, attrs))
7506747b715Smrg            continue;
7516747b715Smrg        if (xf86findOption(cl->option_lst, "Ignore")) {
7526747b715Smrg            ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
7536747b715Smrg            ignore_class = cl->identifier;
7546747b715Smrg        }
7556747b715Smrg    }
7566747b715Smrg
7576747b715Smrg    if (ignore)
7586747b715Smrg        xf86Msg(X_CONFIG, "%s: Ignoring device from InputClass \"%s\"\n",
7599ace9065Smrg                idev->name, ignore_class);
7606747b715Smrg    return ignore;
76105b261ecSmrg}
76205b261ecSmrg
7639ace9065SmrgInputInfoPtr
7649ace9065Smrgxf86AllocateInput(void)
7659ace9065Smrg{
7669ace9065Smrg    InputInfoPtr pInfo;
7679ace9065Smrg
7689ace9065Smrg    pInfo = calloc(sizeof(*pInfo), 1);
7699ace9065Smrg    if (!pInfo)
7709ace9065Smrg        return NULL;
7719ace9065Smrg
7729ace9065Smrg    pInfo->fd = -1;
7739ace9065Smrg    pInfo->type_name = "UNKNOWN";
7749ace9065Smrg
7759ace9065Smrg    return pInfo;
7769ace9065Smrg}
7779ace9065Smrg
7789ace9065Smrg/* Append InputInfoRec to the tail of xf86InputDevs. */
7799ace9065Smrgstatic void
7809ace9065Smrgxf86AddInput(InputDriverPtr drv, InputInfoPtr pInfo)
7819ace9065Smrg{
7829ace9065Smrg    InputInfoPtr *prev = NULL;
7839ace9065Smrg
7849ace9065Smrg    pInfo->drv = drv;
7859ace9065Smrg    pInfo->module = DuplicateModule(drv->module, NULL);
7869ace9065Smrg
78735c4bbdfSmrg    for (prev = &xf86InputDevs; *prev; prev = &(*prev)->next);
7889ace9065Smrg
7899ace9065Smrg    *prev = pInfo;
7909ace9065Smrg    pInfo->next = NULL;
7919ace9065Smrg
79235c4bbdfSmrg    xf86CollectInputOptions(pInfo, (const char **) drv->default_options);
7939ace9065Smrg    xf86OptionListReport(pInfo->options);
7949ace9065Smrg    xf86ProcessCommonOptions(pInfo, pInfo->options);
7959ace9065Smrg}
7969ace9065Smrg
7979ace9065Smrg/*
7989ace9065Smrg * Remove an entry from xf86InputDevs and free all the device's information.
7999ace9065Smrg */
8009ace9065Smrgvoid
8019ace9065Smrgxf86DeleteInput(InputInfoPtr pInp, int flags)
8029ace9065Smrg{
8039ace9065Smrg    /* First check if the inputdev is valid. */
8049ace9065Smrg    if (pInp == NULL)
80535c4bbdfSmrg        return;
8069ace9065Smrg
8079ace9065Smrg    if (pInp->module)
80835c4bbdfSmrg        UnloadModule(pInp->module);
8099ace9065Smrg
8109ace9065Smrg    /* This should *really* be handled in drv->UnInit(dev) call instead, but
8119ace9065Smrg     * if the driver forgets about it make sure we free it or at least crash
8129ace9065Smrg     * with flying colors */
8139ace9065Smrg    free(pInp->private);
8149ace9065Smrg
8159ace9065Smrg    FreeInputAttributes(pInp->attrs);
8169ace9065Smrg
81735c4bbdfSmrg    if (pInp->flags & XI86_SERVER_FD)
81835c4bbdfSmrg        systemd_logind_release_fd(pInp->major, pInp->minor, pInp->fd);
81935c4bbdfSmrg
8209ace9065Smrg    /* Remove the entry from the list. */
8219ace9065Smrg    if (pInp == xf86InputDevs)
82235c4bbdfSmrg        xf86InputDevs = pInp->next;
8239ace9065Smrg    else {
82435c4bbdfSmrg        InputInfoPtr p = xf86InputDevs;
82535c4bbdfSmrg
82635c4bbdfSmrg        while (p && p->next != pInp)
82735c4bbdfSmrg            p = p->next;
82835c4bbdfSmrg        if (p)
82935c4bbdfSmrg            p->next = pInp->next;
83035c4bbdfSmrg        /* Else the entry wasn't in the xf86InputDevs list (ignore this). */
8319ace9065Smrg    }
8329ace9065Smrg
83335c4bbdfSmrg    free((void *) pInp->driver);
83435c4bbdfSmrg    free((void *) pInp->name);
8359ace9065Smrg    xf86optionListFree(pInp->options);
8369ace9065Smrg    free(pInp);
8379ace9065Smrg}
8389ace9065Smrg
8399ace9065Smrg/*
84035c4bbdfSmrg * Apply backend-specific initialization. Invoked after ActivateDevice(),
8419ace9065Smrg * i.e. after the driver successfully completed DEVICE_INIT and the device
8429ace9065Smrg * is advertised.
8439ace9065Smrg * @param dev the device
8449ace9065Smrg * @return Success or an error code
8459ace9065Smrg */
8469ace9065Smrgstatic int
84735c4bbdfSmrgxf86InputDevicePostInit(DeviceIntPtr dev)
84835c4bbdfSmrg{
8499ace9065Smrg    ApplyAccelerationSettings(dev);
85035c4bbdfSmrg    ApplyTransformationMatrix(dev);
851ed6184dfSmrg    ApplyAutoRepeat(dev);
8529ace9065Smrg    return Success;
8539ace9065Smrg}
8549ace9065Smrg
85535c4bbdfSmrgstatic void
85635c4bbdfSmrgxf86stat(const char *path, int *maj, int *min)
85735c4bbdfSmrg{
85835c4bbdfSmrg    struct stat st;
85935c4bbdfSmrg
86035c4bbdfSmrg    if (stat(path, &st) == -1)
86135c4bbdfSmrg        return;
86235c4bbdfSmrg
86335c4bbdfSmrg    *maj = major(st.st_rdev);
86435c4bbdfSmrg    *min = minor(st.st_rdev);
86535c4bbdfSmrg}
86635c4bbdfSmrg
8671b5d61b8Smrgstatic inline InputDriverPtr
8681b5d61b8Smrgxf86LoadInputDriver(const char *driver_name)
8691b5d61b8Smrg{
8701b5d61b8Smrg    InputDriverPtr drv = NULL;
8711b5d61b8Smrg
8721b5d61b8Smrg    /* Memory leak for every attached device if we don't
8731b5d61b8Smrg     * test if the module is already loaded first */
8741b5d61b8Smrg    drv = xf86LookupInputDriver(driver_name);
8751b5d61b8Smrg    if (!drv) {
8761b5d61b8Smrg        if (xf86LoadOneModule(driver_name, NULL))
8771b5d61b8Smrg            drv = xf86LookupInputDriver(driver_name);
8781b5d61b8Smrg    }
8791b5d61b8Smrg
8801b5d61b8Smrg    return drv;
8811b5d61b8Smrg}
8821b5d61b8Smrg
8834642e01fSmrg/**
8844642e01fSmrg * Create a new input device, activate and enable it.
8854642e01fSmrg *
8864642e01fSmrg * Possible return codes:
8874642e01fSmrg *    BadName .. a bad driver name was supplied.
8884642e01fSmrg *    BadImplementation ... The driver does not have a PreInit function. This
8894642e01fSmrg *                          is a driver bug.
8904642e01fSmrg *    BadMatch .. device initialization failed.
8914642e01fSmrg *    BadAlloc .. too many input devices
8924642e01fSmrg *
8934642e01fSmrg * @param idev The device, already set up with identifier, driver, and the
8944642e01fSmrg * options.
8954642e01fSmrg * @param pdev Pointer to the new device, if Success was reported.
8964642e01fSmrg * @param enable Enable the device after activating it.
8974642e01fSmrg *
8984642e01fSmrg * @return Success or an error code
8994642e01fSmrg */
9004642e01fSmrg_X_INTERNAL int
9019ace9065Smrgxf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable)
90205b261ecSmrg{
90305b261ecSmrg    InputDriverPtr drv = NULL;
90405b261ecSmrg    DeviceIntPtr dev = NULL;
905ed6184dfSmrg    Bool paused = FALSE;
9064642e01fSmrg    int rval;
90735c4bbdfSmrg    char *path = NULL;
9084642e01fSmrg
9091b5d61b8Smrg    drv = xf86LoadInputDriver(pInfo->driver);
9104642e01fSmrg    if (!drv) {
9119ace9065Smrg        xf86Msg(X_ERROR, "No input driver matching `%s'\n", pInfo->driver);
9121b5d61b8Smrg
9131b5d61b8Smrg        if (strlen(FALLBACK_INPUT_DRIVER) > 0) {
9141b5d61b8Smrg            xf86Msg(X_INFO, "Falling back to input driver `%s'\n",
9151b5d61b8Smrg                    FALLBACK_INPUT_DRIVER);
9161b5d61b8Smrg            drv = xf86LoadInputDriver(FALLBACK_INPUT_DRIVER);
9171b5d61b8Smrg            if (drv) {
9181b5d61b8Smrg                free(pInfo->driver);
9191b5d61b8Smrg                pInfo->driver = strdup(FALLBACK_INPUT_DRIVER);
9201b5d61b8Smrg            }
9211b5d61b8Smrg        }
9221b5d61b8Smrg        if (!drv) {
9231b5d61b8Smrg            rval = BadName;
9241b5d61b8Smrg            goto unwind;
9251b5d61b8Smrg        }
9261b5d61b8Smrg    }
9271b5d61b8Smrg
9281b5d61b8Smrg    xf86Msg(X_INFO, "Using input driver '%s' for '%s'\n", drv->driverName,
9291b5d61b8Smrg            pInfo->name);
9301b5d61b8Smrg
9311b5d61b8Smrg    if (!drv->PreInit) {
9321b5d61b8Smrg        xf86Msg(X_ERROR,
9331b5d61b8Smrg                "Input driver `%s' has no PreInit function (ignoring)\n",
9341b5d61b8Smrg                drv->driverName);
9351b5d61b8Smrg        rval = BadImplementation;
9364642e01fSmrg        goto unwind;
9374642e01fSmrg    }
9384642e01fSmrg
93935c4bbdfSmrg    path = xf86CheckStrOption(pInfo->options, "Device", NULL);
94035c4bbdfSmrg    if (path && pInfo->major == 0 && pInfo->minor == 0)
94135c4bbdfSmrg        xf86stat(path, &pInfo->major, &pInfo->minor);
94235c4bbdfSmrg
94335c4bbdfSmrg    if (path && (drv->capabilities & XI86_DRV_CAP_SERVER_FD)){
94435c4bbdfSmrg        int fd = systemd_logind_take_fd(pInfo->major, pInfo->minor,
94535c4bbdfSmrg                                        path, &paused);
94635c4bbdfSmrg        if (fd != -1) {
94735c4bbdfSmrg            if (paused) {
94835c4bbdfSmrg                /* Put on new_input_devices list for delayed probe */
9491b5d61b8Smrg                PausedInputDevicePtr new_device = xnfalloc(sizeof *new_device);
9501b5d61b8Smrg                new_device->pInfo = pInfo;
9511b5d61b8Smrg
9521b5d61b8Smrg                xorg_list_append(&new_device->node, &new_input_devices_list);
95335c4bbdfSmrg                systemd_logind_release_fd(pInfo->major, pInfo->minor, fd);
95435c4bbdfSmrg                free(path);
95535c4bbdfSmrg                return BadMatch;
95635c4bbdfSmrg            }
95735c4bbdfSmrg            pInfo->fd = fd;
95835c4bbdfSmrg            pInfo->flags |= XI86_SERVER_FD;
95935c4bbdfSmrg            pInfo->options = xf86ReplaceIntOption(pInfo->options, "fd", fd);
96035c4bbdfSmrg        }
96135c4bbdfSmrg    }
96235c4bbdfSmrg
96335c4bbdfSmrg    free(path);
96435c4bbdfSmrg
9659ace9065Smrg    xf86AddInput(drv, pInfo);
9664642e01fSmrg
9671b5d61b8Smrg    input_lock();
9689ace9065Smrg    rval = drv->PreInit(drv, pInfo, 0);
9691b5d61b8Smrg    input_unlock();
9709ace9065Smrg
9719ace9065Smrg    if (rval != Success) {
9729ace9065Smrg        xf86Msg(X_ERROR, "PreInit returned %d for \"%s\"\n", rval, pInfo->name);
9734642e01fSmrg        goto unwind;
9744642e01fSmrg    }
9754642e01fSmrg
97635c4bbdfSmrg    if (!(dev = xf86ActivateDevice(pInfo))) {
9774642e01fSmrg        rval = BadAlloc;
9784642e01fSmrg        goto unwind;
9794642e01fSmrg    }
9804642e01fSmrg
9816747b715Smrg    rval = ActivateDevice(dev, TRUE);
98235c4bbdfSmrg    if (rval != Success) {
9839ace9065Smrg        xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", pInfo->name);
9846747b715Smrg        RemoveDevice(dev, TRUE);
9854642e01fSmrg        goto unwind;
9864642e01fSmrg    }
9874642e01fSmrg
9889ace9065Smrg    rval = xf86InputDevicePostInit(dev);
98935c4bbdfSmrg    if (rval != Success) {
99035c4bbdfSmrg        xf86Msg(X_ERROR, "Couldn't post-init device \"%s\"\n", pInfo->name);
99135c4bbdfSmrg        RemoveDevice(dev, TRUE);
99235c4bbdfSmrg        goto unwind;
9939ace9065Smrg    }
9949ace9065Smrg
9954642e01fSmrg    /* Enable it if it's properly initialised and we're currently in the VT */
99635c4bbdfSmrg    if (enable && dev->inited && dev->startup && xf86VTOwner()) {
9971b5d61b8Smrg        input_lock();
9986747b715Smrg        EnableDevice(dev, TRUE);
99935c4bbdfSmrg        if (!dev->enabled) {
10009ace9065Smrg            xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", pInfo->name);
1001475c125cSmrg            RemoveDevice(dev, TRUE);
10026747b715Smrg            rval = BadMatch;
10031b5d61b8Smrg            input_unlock();
10046747b715Smrg            goto unwind;
10056747b715Smrg        }
10064642e01fSmrg        /* send enter/leave event, update sprite window */
10074642e01fSmrg        CheckMotion(NULL, dev);
10081b5d61b8Smrg        input_unlock();
10094642e01fSmrg    }
10104642e01fSmrg
10114642e01fSmrg    *pdev = dev;
10124642e01fSmrg    return Success;
10134642e01fSmrg
101435c4bbdfSmrg unwind:
101535c4bbdfSmrg    if (pInfo) {
101635c4bbdfSmrg        if (drv && drv->UnInit)
10174642e01fSmrg            drv->UnInit(drv, pInfo, 0);
10184642e01fSmrg        else
10194642e01fSmrg            xf86DeleteInput(pInfo, 0);
10204642e01fSmrg    }
10214642e01fSmrg    return rval;
10224642e01fSmrg}
10234642e01fSmrg
10246747b715Smrgint
102535c4bbdfSmrgNewInputDeviceRequest(InputOption *options, InputAttributes * attrs,
102635c4bbdfSmrg                      DeviceIntPtr *pdev)
10274642e01fSmrg{
10289ace9065Smrg    InputInfoPtr pInfo = NULL;
10294642e01fSmrg    InputOption *option = NULL;
103005b261ecSmrg    int rval = Success;
103105b261ecSmrg    int is_auto = 0;
103205b261ecSmrg
10339ace9065Smrg    pInfo = xf86AllocateInput();
10349ace9065Smrg    if (!pInfo)
103505b261ecSmrg        return BadAlloc;
103605b261ecSmrg
103735c4bbdfSmrg    nt_list_for_each_entry(option, options, list.next) {
103835c4bbdfSmrg        const char *key = input_option_get_key(option);
103935c4bbdfSmrg        const char *value = input_option_get_value(option);
104035c4bbdfSmrg
104135c4bbdfSmrg        if (strcasecmp(key, "driver") == 0) {
10429ace9065Smrg            if (pInfo->driver) {
104305b261ecSmrg                rval = BadRequest;
104405b261ecSmrg                goto unwind;
104505b261ecSmrg            }
104635c4bbdfSmrg            pInfo->driver = xstrdup(value);
10479ace9065Smrg            if (!pInfo->driver) {
104805b261ecSmrg                rval = BadAlloc;
104905b261ecSmrg                goto unwind;
105005b261ecSmrg            }
105105b261ecSmrg        }
105205b261ecSmrg
105335c4bbdfSmrg        if (strcasecmp(key, "name") == 0 || strcasecmp(key, "identifier") == 0) {
10549ace9065Smrg            if (pInfo->name) {
105505b261ecSmrg                rval = BadRequest;
105605b261ecSmrg                goto unwind;
105705b261ecSmrg            }
105835c4bbdfSmrg            pInfo->name = xstrdup(value);
10599ace9065Smrg            if (!pInfo->name) {
106005b261ecSmrg                rval = BadAlloc;
106105b261ecSmrg                goto unwind;
106205b261ecSmrg            }
106305b261ecSmrg        }
106405b261ecSmrg
106535c4bbdfSmrg        if (strcmp(key, "_source") == 0 &&
106635c4bbdfSmrg            (strcmp(value, "server/hal") == 0 ||
106735c4bbdfSmrg             strcmp(value, "server/udev") == 0 ||
106835c4bbdfSmrg             strcmp(value, "server/wscons") == 0)) {
10696747b715Smrg            is_auto = 1;
107005b261ecSmrg            if (!xf86Info.autoAddDevices) {
107105b261ecSmrg                rval = BadMatch;
107205b261ecSmrg                goto unwind;
107305b261ecSmrg            }
10746747b715Smrg        }
107535c4bbdfSmrg
107635c4bbdfSmrg        if (strcmp(key, "major") == 0)
107735c4bbdfSmrg            pInfo->major = atoi(value);
107835c4bbdfSmrg
107935c4bbdfSmrg        if (strcmp(key, "minor") == 0)
108035c4bbdfSmrg            pInfo->minor = atoi(value);
10816747b715Smrg    }
108205b261ecSmrg
108335c4bbdfSmrg    nt_list_for_each_entry(option, options, list.next) {
108435c4bbdfSmrg        /* Copy option key/value strings from the provided list */
108535c4bbdfSmrg        pInfo->options = xf86AddNewOption(pInfo->options,
108635c4bbdfSmrg                                          input_option_get_key(option),
108735c4bbdfSmrg                                          input_option_get_value(option));
10886747b715Smrg    }
10896747b715Smrg
10906747b715Smrg    /* Apply InputClass settings */
10916747b715Smrg    if (attrs) {
10929ace9065Smrg        if (IgnoreInputClass(pInfo, attrs)) {
10936747b715Smrg            rval = BadIDChoice;
10946747b715Smrg            goto unwind;
109505b261ecSmrg        }
10966747b715Smrg
10979ace9065Smrg        rval = MergeInputClasses(pInfo, attrs);
10986747b715Smrg        if (rval != Success)
10996747b715Smrg            goto unwind;
11006747b715Smrg
11019ace9065Smrg        pInfo->attrs = DuplicateInputAttributes(attrs);
110205b261ecSmrg    }
11036747b715Smrg
1104475c125cSmrg    if (!pInfo->name) {
1105475c125cSmrg        xf86Msg(X_INFO, "No identifier specified, ignoring this device.\n");
110605b261ecSmrg        rval = BadRequest;
110705b261ecSmrg        goto unwind;
110805b261ecSmrg    }
110905b261ecSmrg
1110475c125cSmrg    if (!pInfo->driver) {
1111475c125cSmrg        xf86Msg(X_INFO, "No input driver specified, ignoring this device.\n");
111235c4bbdfSmrg        xf86Msg(X_INFO,
111335c4bbdfSmrg                "This device may have been added with another device file.\n");
1114475c125cSmrg        rval = BadRequest;
11159ace9065Smrg        goto unwind;
111605b261ecSmrg    }
111705b261ecSmrg
11189ace9065Smrg    rval = xf86NewInputDevice(pInfo, pdev,
111935c4bbdfSmrg                              (!is_auto ||
112035c4bbdfSmrg                               (is_auto && xf86Info.autoEnableDevices)));
11219ace9065Smrg
11229ace9065Smrg    return rval;
112305b261ecSmrg
112435c4bbdfSmrg unwind:
11256747b715Smrg    if (is_auto && !xf86Info.autoAddDevices)
11266747b715Smrg        xf86Msg(X_INFO, "AutoAddDevices is off - not adding device.\n");
11279ace9065Smrg    xf86DeleteInput(pInfo, 0);
112805b261ecSmrg    return rval;
112905b261ecSmrg}
113005b261ecSmrg
11316747b715Smrgvoid
113205b261ecSmrgDeleteInputDeviceRequest(DeviceIntPtr pDev)
113305b261ecSmrg{
11349ace9065Smrg    InputInfoPtr pInfo = (InputInfoPtr) pDev->public.devicePrivate;
11354642e01fSmrg    InputDriverPtr drv = NULL;
11366747b715Smrg    Bool isMaster = IsMaster(pDev);
113705b261ecSmrg
113835c4bbdfSmrg    if (pInfo)                  /* need to get these before RemoveDevice */
11394642e01fSmrg        drv = pInfo->drv;
11404642e01fSmrg
11411b5d61b8Smrg    input_lock();
11426747b715Smrg    RemoveDevice(pDev, TRUE);
114305b261ecSmrg
114435c4bbdfSmrg    if (!isMaster && pInfo != NULL) {
114535c4bbdfSmrg        if (drv->UnInit)
11464642e01fSmrg            drv->UnInit(drv, pInfo, 0);
11474642e01fSmrg        else
11484642e01fSmrg            xf86DeleteInput(pInfo, 0);
11494642e01fSmrg    }
11501b5d61b8Smrg    input_unlock();
11511b5d61b8Smrg}
11521b5d61b8Smrg
11531b5d61b8Smrgvoid
11541b5d61b8SmrgRemoveInputDeviceTraces(const char *config_info)
11551b5d61b8Smrg{
11561b5d61b8Smrg    PausedInputDevicePtr d, tmp;
11571b5d61b8Smrg
11581b5d61b8Smrg    xorg_list_for_each_entry_safe(d, tmp, &new_input_devices_list, node) {
11591b5d61b8Smrg        const char *ci = xf86findOptionValue(d->pInfo->options, "config_info");
11601b5d61b8Smrg        if (!ci || strcmp(ci, config_info) != 0)
11611b5d61b8Smrg            continue;
11621b5d61b8Smrg
11631b5d61b8Smrg        xorg_list_del(&d->node);
11641b5d61b8Smrg        free(d);
11651b5d61b8Smrg    }
116605b261ecSmrg}
116705b261ecSmrg
116835c4bbdfSmrg/*
116905b261ecSmrg * convenient functions to post events
117005b261ecSmrg */
117105b261ecSmrg
11726747b715Smrgvoid
117335c4bbdfSmrgxf86PostMotionEvent(DeviceIntPtr device,
117435c4bbdfSmrg                    int is_absolute, int first_valuator, int num_valuators, ...)
117505b261ecSmrg{
117605b261ecSmrg    va_list var;
117705b261ecSmrg    int i = 0;
11789ace9065Smrg    ValuatorMask mask;
117905b261ecSmrg
11806747b715Smrg    XI_VERIFY_VALUATORS(num_valuators);
118105b261ecSmrg
11829ace9065Smrg    valuator_mask_zero(&mask);
118305b261ecSmrg    va_start(var, num_valuators);
118405b261ecSmrg    for (i = 0; i < num_valuators; i++)
11859ace9065Smrg        valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
118635c4bbdfSmrg
118705b261ecSmrg    va_end(var);
118805b261ecSmrg
11899ace9065Smrg    xf86PostMotionEventM(device, is_absolute, &mask);
119005b261ecSmrg}
119105b261ecSmrg
11926747b715Smrgvoid
119335c4bbdfSmrgxf86PostMotionEventP(DeviceIntPtr device,
119435c4bbdfSmrg                     int is_absolute,
119535c4bbdfSmrg                     int first_valuator,
119635c4bbdfSmrg                     int num_valuators, const int *valuators)
11979ace9065Smrg{
11989ace9065Smrg    ValuatorMask mask;
11999ace9065Smrg
12009ace9065Smrg    XI_VERIFY_VALUATORS(num_valuators);
12019ace9065Smrg
12029ace9065Smrg    valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
12039ace9065Smrg    xf86PostMotionEventM(device, is_absolute, &mask);
12049ace9065Smrg}
12059ace9065Smrg
120635c4bbdfSmrgstatic int
120735c4bbdfSmrgxf86CheckMotionEvent4DGA(DeviceIntPtr device, int is_absolute,
120835c4bbdfSmrg                         const ValuatorMask *mask)
120905b261ecSmrg{
121035c4bbdfSmrg    int stolen = 0;
121105b261ecSmrg
12121b5d61b8Smrg#ifdef XFreeXDGA
121335c4bbdfSmrg    ScreenPtr scr = NULL;
121435c4bbdfSmrg    int idx = 0, i;
121535c4bbdfSmrg
12164642e01fSmrg    /* The evdev driver may not always send all axes across. */
121735c4bbdfSmrg    if (valuator_mask_isset(mask, 0) || valuator_mask_isset(mask, 1)) {
121835c4bbdfSmrg        scr = miPointerGetScreen(device);
121935c4bbdfSmrg        if (scr) {
12209ace9065Smrg            int dx = 0, dy = 0;
12219ace9065Smrg
122235c4bbdfSmrg            idx = scr->myNum;
122335c4bbdfSmrg
122435c4bbdfSmrg            if (valuator_mask_isset(mask, 0)) {
12259ace9065Smrg                dx = valuator_mask_get(mask, 0);
12264642e01fSmrg                if (is_absolute)
12274642e01fSmrg                    dx -= device->last.valuators[0];
122835c4bbdfSmrg                else if (valuator_mask_has_unaccelerated(mask))
122935c4bbdfSmrg                    dx = valuator_mask_get_unaccelerated(mask, 0);
123005b261ecSmrg            }
12314642e01fSmrg
123235c4bbdfSmrg            if (valuator_mask_isset(mask, 1)) {
12339ace9065Smrg                dy = valuator_mask_get(mask, 1);
12344642e01fSmrg                if (is_absolute)
12354642e01fSmrg                    dy -= device->last.valuators[1];
123635c4bbdfSmrg                else if (valuator_mask_has_unaccelerated(mask))
123735c4bbdfSmrg                    dy = valuator_mask_get_unaccelerated(mask, 1);
12384642e01fSmrg            }
12394642e01fSmrg
124035c4bbdfSmrg            if (DGAStealMotionEvent(device, idx, dx, dy))
124135c4bbdfSmrg                stolen = 1;
124205b261ecSmrg        }
124335c4bbdfSmrg    }
124435c4bbdfSmrg
124535c4bbdfSmrg    for (i = 2; i < valuator_mask_size(mask); i++) {
124635c4bbdfSmrg        AxisInfoPtr ax;
124735c4bbdfSmrg        double incr;
124835c4bbdfSmrg        int val, button;
124935c4bbdfSmrg
125035c4bbdfSmrg        if (i >= device->valuator->numAxes)
125135c4bbdfSmrg            break;
125235c4bbdfSmrg
125335c4bbdfSmrg        if (!valuator_mask_isset(mask, i))
125435c4bbdfSmrg            continue;
125535c4bbdfSmrg
125635c4bbdfSmrg        ax = &device->valuator->axes[i];
125735c4bbdfSmrg
125835c4bbdfSmrg        if (ax->scroll.type == SCROLL_TYPE_NONE)
125935c4bbdfSmrg            continue;
126035c4bbdfSmrg
126135c4bbdfSmrg        if (!scr) {
126235c4bbdfSmrg            scr = miPointerGetScreen(device);
126335c4bbdfSmrg            if (!scr)
126435c4bbdfSmrg                break;
126535c4bbdfSmrg            idx = scr->myNum;
126635c4bbdfSmrg        }
126735c4bbdfSmrg
126835c4bbdfSmrg        incr = ax->scroll.increment;
126935c4bbdfSmrg        val = valuator_mask_get(mask, i);
127035c4bbdfSmrg
127135c4bbdfSmrg        if (ax->scroll.type == SCROLL_TYPE_VERTICAL) {
127235c4bbdfSmrg            if (incr * val < 0)
127335c4bbdfSmrg                button = 4; /* up */
127435c4bbdfSmrg            else
127535c4bbdfSmrg                button = 5; /* down */
127635c4bbdfSmrg        } else { /* SCROLL_TYPE_HORIZONTAL */
127735c4bbdfSmrg            if (incr * val < 0)
127835c4bbdfSmrg                button = 6; /* left */
127935c4bbdfSmrg            else
128035c4bbdfSmrg                button = 7; /* right */
128135c4bbdfSmrg        }
128235c4bbdfSmrg
128335c4bbdfSmrg        if (DGAStealButtonEvent(device, idx, button, 1) &&
128435c4bbdfSmrg                DGAStealButtonEvent(device, idx, button, 0))
128535c4bbdfSmrg            stolen = 1;
128635c4bbdfSmrg    }
128735c4bbdfSmrg
128805b261ecSmrg#endif
128905b261ecSmrg
129035c4bbdfSmrg    return stolen;
129135c4bbdfSmrg}
129235c4bbdfSmrg
129335c4bbdfSmrgvoid
129435c4bbdfSmrgxf86PostMotionEventM(DeviceIntPtr device,
129535c4bbdfSmrg                     int is_absolute, const ValuatorMask *mask)
129635c4bbdfSmrg{
129735c4bbdfSmrg    int flags = 0;
129805b261ecSmrg
129935c4bbdfSmrg    if (xf86CheckMotionEvent4DGA(device, is_absolute, mask))
130035c4bbdfSmrg        return;
130135c4bbdfSmrg
130235c4bbdfSmrg    if (valuator_mask_num_valuators(mask) > 0) {
130335c4bbdfSmrg        if (is_absolute)
130435c4bbdfSmrg            flags = POINTER_ABSOLUTE;
130535c4bbdfSmrg        else
130635c4bbdfSmrg            flags = POINTER_RELATIVE | POINTER_ACCELERATE;
130705b261ecSmrg    }
130835c4bbdfSmrg
130935c4bbdfSmrg    QueuePointerEvents(device, MotionNotify, 0, flags, mask);
131005b261ecSmrg}
131105b261ecSmrg
13126747b715Smrgvoid
131335c4bbdfSmrgxf86PostProximityEvent(DeviceIntPtr device,
131435c4bbdfSmrg                       int is_in, int first_valuator, int num_valuators, ...)
131505b261ecSmrg{
131605b261ecSmrg    va_list var;
13176747b715Smrg    int i;
13189ace9065Smrg    ValuatorMask mask;
131905b261ecSmrg
13206747b715Smrg    XI_VERIFY_VALUATORS(num_valuators);
132105b261ecSmrg
13229ace9065Smrg    valuator_mask_zero(&mask);
132305b261ecSmrg    va_start(var, num_valuators);
132405b261ecSmrg    for (i = 0; i < num_valuators; i++)
13259ace9065Smrg        valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
132635c4bbdfSmrg
132705b261ecSmrg    va_end(var);
132805b261ecSmrg
13299ace9065Smrg    xf86PostProximityEventM(device, is_in, &mask);
13306747b715Smrg}
13316747b715Smrg
13326747b715Smrgvoid
133335c4bbdfSmrgxf86PostProximityEventP(DeviceIntPtr device,
133435c4bbdfSmrg                        int is_in,
133535c4bbdfSmrg                        int first_valuator,
133635c4bbdfSmrg                        int num_valuators, const int *valuators)
13376747b715Smrg{
13389ace9065Smrg    ValuatorMask mask;
13396747b715Smrg
13406747b715Smrg    XI_VERIFY_VALUATORS(num_valuators);
13416747b715Smrg
13429ace9065Smrg    valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
13439ace9065Smrg    xf86PostProximityEventM(device, is_in, &mask);
13449ace9065Smrg}
13459ace9065Smrg
13469ace9065Smrgvoid
134735c4bbdfSmrgxf86PostProximityEventM(DeviceIntPtr device,
134835c4bbdfSmrg                        int is_in, const ValuatorMask *mask)
13499ace9065Smrg{
135035c4bbdfSmrg    QueueProximityEvents(device, is_in ? ProximityIn : ProximityOut, mask);
135105b261ecSmrg}
135205b261ecSmrg
13536747b715Smrgvoid
135435c4bbdfSmrgxf86PostButtonEvent(DeviceIntPtr device,
135535c4bbdfSmrg                    int is_absolute,
135635c4bbdfSmrg                    int button,
135735c4bbdfSmrg                    int is_down, int first_valuator, int num_valuators, ...)
135805b261ecSmrg{
135905b261ecSmrg    va_list var;
13609ace9065Smrg    ValuatorMask mask;
13616747b715Smrg    int i = 0;
13626747b715Smrg
13636747b715Smrg    XI_VERIFY_VALUATORS(num_valuators);
13646747b715Smrg
13659ace9065Smrg    valuator_mask_zero(&mask);
13669ace9065Smrg
13676747b715Smrg    va_start(var, num_valuators);
13686747b715Smrg    for (i = 0; i < num_valuators; i++)
13699ace9065Smrg        valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
137035c4bbdfSmrg
13716747b715Smrg    va_end(var);
13726747b715Smrg
13739ace9065Smrg    xf86PostButtonEventM(device, is_absolute, button, is_down, &mask);
13746747b715Smrg}
13756747b715Smrg
13766747b715Smrgvoid
137735c4bbdfSmrgxf86PostButtonEventP(DeviceIntPtr device,
137835c4bbdfSmrg                     int is_absolute,
137935c4bbdfSmrg                     int button,
138035c4bbdfSmrg                     int is_down,
138135c4bbdfSmrg                     int first_valuator,
138235c4bbdfSmrg                     int num_valuators, const int *valuators)
13836747b715Smrg{
13849ace9065Smrg    ValuatorMask mask;
13856747b715Smrg
13866747b715Smrg    XI_VERIFY_VALUATORS(num_valuators);
13876747b715Smrg
13889ace9065Smrg    valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
13899ace9065Smrg    xf86PostButtonEventM(device, is_absolute, button, is_down, &mask);
13909ace9065Smrg}
13919ace9065Smrg
13929ace9065Smrgvoid
139335c4bbdfSmrgxf86PostButtonEventM(DeviceIntPtr device,
139435c4bbdfSmrg                     int is_absolute,
139535c4bbdfSmrg                     int button, int is_down, const ValuatorMask *mask)
13969ace9065Smrg{
13979ace9065Smrg    int flags = 0;
13989ace9065Smrg
139935c4bbdfSmrg    if (valuator_mask_num_valuators(mask) > 0) {
14009ace9065Smrg        if (is_absolute)
14019ace9065Smrg            flags = POINTER_ABSOLUTE;
14029ace9065Smrg        else
14039ace9065Smrg            flags = POINTER_RELATIVE | POINTER_ACCELERATE;
14049ace9065Smrg    }
140505b261ecSmrg
14061b5d61b8Smrg#ifdef XFreeXDGA
14074642e01fSmrg    if (miPointerGetScreen(device)) {
14089ace9065Smrg        int index = miPointerGetScreen(device)->myNum;
14099ace9065Smrg
14104642e01fSmrg        if (DGAStealButtonEvent(device, index, button, is_down))
141105b261ecSmrg            return;
141205b261ecSmrg    }
141305b261ecSmrg#endif
141405b261ecSmrg
141535c4bbdfSmrg    QueuePointerEvents(device,
141635c4bbdfSmrg                       is_down ? ButtonPress : ButtonRelease, button,
141735c4bbdfSmrg                       flags, mask);
141805b261ecSmrg}
141905b261ecSmrg
14206747b715Smrgvoid
142135c4bbdfSmrgxf86PostKeyEvent(DeviceIntPtr device, unsigned int key_code, int is_down)
142205b261ecSmrg{
142335c4bbdfSmrg    xf86PostKeyEventM(device, key_code, is_down);
14246747b715Smrg}
14256747b715Smrg
14266747b715Smrgvoid
142735c4bbdfSmrgxf86PostKeyEventP(DeviceIntPtr device,
142835c4bbdfSmrg                  unsigned int key_code,
142935c4bbdfSmrg                  int is_down)
14306747b715Smrg{
143135c4bbdfSmrg    xf86PostKeyEventM(device, key_code, is_down);
14329ace9065Smrg}
14339ace9065Smrg
14349ace9065Smrgvoid
143535c4bbdfSmrgxf86PostKeyEventM(DeviceIntPtr device, unsigned int key_code, int is_down)
14369ace9065Smrg{
14371b5d61b8Smrg#ifdef XFreeXDGA
14389ace9065Smrg    DeviceIntPtr pointer;
14399ace9065Smrg
14409ace9065Smrg    /* Some pointers send key events, paired device is wrong then. */
144135c4bbdfSmrg    pointer = GetMaster(device, POINTER_OR_FLOAT);
144235c4bbdfSmrg
14439ace9065Smrg    if (miPointerGetScreen(pointer)) {
14449ace9065Smrg        int index = miPointerGetScreen(pointer)->myNum;
14459ace9065Smrg
14469ace9065Smrg        if (DGAStealKeyEvent(device, index, key_code, is_down))
14479ace9065Smrg            return;
14489ace9065Smrg    }
14499ace9065Smrg#endif
14509ace9065Smrg
145135c4bbdfSmrg    QueueKeyboardEvents(device, is_down ? KeyPress : KeyRelease, key_code);
145205b261ecSmrg}
145305b261ecSmrg
14546747b715Smrgvoid
145535c4bbdfSmrgxf86PostKeyboardEvent(DeviceIntPtr device, unsigned int key_code, int is_down)
145605b261ecSmrg{
14579ace9065Smrg    ValuatorMask mask;
14589ace9065Smrg
14599ace9065Smrg    valuator_mask_zero(&mask);
146035c4bbdfSmrg    xf86PostKeyEventM(device, key_code, is_down);
146105b261ecSmrg}
146205b261ecSmrg
14639ace9065SmrgInputInfoPtr
14646747b715Smrgxf86FirstLocalDevice(void)
146505b261ecSmrg{
146605b261ecSmrg    return xf86InputDevs;
146705b261ecSmrg}
146805b261ecSmrg
146935c4bbdfSmrg/*
147005b261ecSmrg * Cx     - raw data from touch screen
14719ace9065Smrg * to_max - scaled highest dimension
147205b261ecSmrg *          (remember, this is of rows - 1 because of 0 origin)
14739ace9065Smrg * to_min  - scaled lowest dimension
14749ace9065Smrg * from_max - highest raw value from touch screen calibration
14759ace9065Smrg * from_min  - lowest raw value from touch screen calibration
147605b261ecSmrg *
147705b261ecSmrg * This function is the same for X or Y coordinates.
147805b261ecSmrg * You may have to reverse the high and low values to compensate for
1479ed6184dfSmrg * different origins on the touch screen vs X.
14809ace9065Smrg *
14819ace9065Smrg * e.g. to scale from device coordinates into screen coordinates, call
14829ace9065Smrg * xf86ScaleAxis(x, 0, screen_width, dev_min, dev_max);
148305b261ecSmrg */
148405b261ecSmrg
14856747b715Smrgint
148635c4bbdfSmrgxf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min)
148705b261ecSmrg{
148805b261ecSmrg    int X;
14899ace9065Smrg    int64_t to_width = to_max - to_min;
14909ace9065Smrg    int64_t from_width = from_max - from_min;
149105b261ecSmrg
14929ace9065Smrg    if (from_width) {
149335c4bbdfSmrg        X = (int) (((to_width * (Cx - from_min)) / from_width) + to_min);
149405b261ecSmrg    }
149505b261ecSmrg    else {
149635c4bbdfSmrg        X = 0;
149735c4bbdfSmrg        ErrorF("Divide by Zero in xf86ScaleAxis\n");
149805b261ecSmrg    }
149935c4bbdfSmrg
15009ace9065Smrg    if (X > to_max)
150135c4bbdfSmrg        X = to_max;
15029ace9065Smrg    if (X < to_min)
150335c4bbdfSmrg        X = to_min;
150405b261ecSmrg
150535c4bbdfSmrg    return X;
150605b261ecSmrg}
150705b261ecSmrg
150835c4bbdfSmrgBool
150935c4bbdfSmrgxf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval,
151035c4bbdfSmrg                           int maxval, int resolution, int min_res, int max_res,
151135c4bbdfSmrg                           int mode)
151205b261ecSmrg{
151305b261ecSmrg    if (!dev || !dev->valuator)
151435c4bbdfSmrg        return FALSE;
151505b261ecSmrg
151635c4bbdfSmrg    return InitValuatorAxisStruct(dev, axnum, label, minval, maxval, resolution,
151735c4bbdfSmrg                                  min_res, max_res, mode);
151805b261ecSmrg}
151905b261ecSmrg
152005b261ecSmrg/*
152135c4bbdfSmrg * Set the valuator values to be in sync with dix/event.c
152205b261ecSmrg * DefineInitialRootWindow().
152305b261ecSmrg */
15246747b715Smrgvoid
152505b261ecSmrgxf86InitValuatorDefaults(DeviceIntPtr dev, int axnum)
152605b261ecSmrg{
152705b261ecSmrg    if (axnum == 0) {
152835c4bbdfSmrg        dev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
15294642e01fSmrg        dev->last.valuators[0] = dev->valuator->axisVal[0];
153005b261ecSmrg    }
153105b261ecSmrg    else if (axnum == 1) {
153235c4bbdfSmrg        dev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
15334642e01fSmrg        dev->last.valuators[1] = dev->valuator->axisVal[1];
153405b261ecSmrg    }
153505b261ecSmrg}
153605b261ecSmrg
153705b261ecSmrg/**
153805b261ecSmrg * Deactivate a device. Call this function from the driver if you receive a
153905b261ecSmrg * read error or something else that spoils your day.
154005b261ecSmrg * Device will be moved to the off_devices list, but it will still be there
154105b261ecSmrg * until you really clean up after it.
154205b261ecSmrg * Notifies the client about an inactive device.
154335c4bbdfSmrg *
154405b261ecSmrg * @param panic True if device is unrecoverable and needs to be removed.
154505b261ecSmrg */
15466747b715Smrgvoid
154705b261ecSmrgxf86DisableDevice(DeviceIntPtr dev, Bool panic)
154805b261ecSmrg{
154935c4bbdfSmrg    if (!panic) {
15506747b715Smrg        DisableDevice(dev, TRUE);
155135c4bbdfSmrg    }
155235c4bbdfSmrg    else {
15536747b715Smrg        SendDevicePresenceEvent(dev->id, DeviceUnrecoverable);
155405b261ecSmrg        DeleteInputDeviceRequest(dev);
155505b261ecSmrg    }
155605b261ecSmrg}
155705b261ecSmrg
155805b261ecSmrg/**
155905b261ecSmrg * Reactivate a device. Call this function from the driver if you just found
156005b261ecSmrg * out that the read error wasn't quite that bad after all.
156135c4bbdfSmrg * Device will be re-activated, and an event sent to the client.
156205b261ecSmrg */
15636747b715Smrgvoid
156405b261ecSmrgxf86EnableDevice(DeviceIntPtr dev)
156505b261ecSmrg{
15666747b715Smrg    EnableDevice(dev, TRUE);
156705b261ecSmrg}
156805b261ecSmrg
156935c4bbdfSmrg/**
157035c4bbdfSmrg * Post a touch event with optional valuators.  If this is the first touch in
157135c4bbdfSmrg * the sequence, at least x & y valuators must be provided. The driver is
157235c4bbdfSmrg * responsible for maintaining the correct event sequence (TouchBegin, TouchUpdate,
157335c4bbdfSmrg * TouchEnd). Submitting an update or end event for a unregistered touchid will
157435c4bbdfSmrg * result in errors.
157535c4bbdfSmrg * Touch IDs may be reused by the driver but only after a TouchEnd has been
157635c4bbdfSmrg * submitted for that touch ID.
157735c4bbdfSmrg *
157835c4bbdfSmrg * @param dev The device to post the event for
157935c4bbdfSmrg * @param touchid The touchid of the current touch event. Must be an
158035c4bbdfSmrg * existing ID for TouchUpdate or TouchEnd events
158135c4bbdfSmrg * @param type One of XI_TouchBegin, XI_TouchUpdate, XI_TouchEnd
158235c4bbdfSmrg * @param flags Flags for this event
158335c4bbdfSmrg * @param The valuator mask with all valuators set for this event.
158435c4bbdfSmrg */
158535c4bbdfSmrgvoid
158635c4bbdfSmrgxf86PostTouchEvent(DeviceIntPtr dev, uint32_t touchid, uint16_t type,
158735c4bbdfSmrg                   uint32_t flags, const ValuatorMask *mask)
158835c4bbdfSmrg{
158935c4bbdfSmrg
159035c4bbdfSmrg    QueueTouchEvents(dev, type, touchid, flags, mask);
159135c4bbdfSmrg}
159235c4bbdfSmrg
1593ed6184dfSmrg/**
1594ed6184dfSmrg * Post a gesture pinch event.  The driver is responsible for maintaining the
1595ed6184dfSmrg * correct event sequence (GesturePinchBegin, GesturePinchUpdate,
1596ed6184dfSmrg * GesturePinchEnd).
1597ed6184dfSmrg *
1598ed6184dfSmrg * @param dev The device to post the event for
1599ed6184dfSmrg * @param type One of XI_GesturePinchBegin, XI_GesturePinchUpdate,
1600ed6184dfSmrg *        XI_GesturePinchEnd
1601ed6184dfSmrg * @param num_touches The number of touches in the gesture
1602ed6184dfSmrg * @param flags Flags for this event
1603ed6184dfSmrg * @param delta_x,delta_y accelerated relative motion delta
1604ed6184dfSmrg * @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta
1605ed6184dfSmrg * @param scale absolute scale of a pinch gesture
1606ed6184dfSmrg * @param delta_angle the ange delta in degrees between the last and the current pinch event.
1607ed6184dfSmrg */
1608ed6184dfSmrgvoid
1609ed6184dfSmrgxf86PostGesturePinchEvent(DeviceIntPtr dev, uint16_t type,
1610ed6184dfSmrg                          uint16_t num_touches, uint32_t flags,
1611ed6184dfSmrg                          double delta_x, double delta_y,
1612ed6184dfSmrg                          double delta_unaccel_x,
1613ed6184dfSmrg                          double delta_unaccel_y,
1614ed6184dfSmrg                          double scale, double delta_angle)
1615ed6184dfSmrg{
1616ed6184dfSmrg    QueueGesturePinchEvents(dev, type, num_touches, flags, delta_x, delta_y,
1617ed6184dfSmrg                            delta_unaccel_x, delta_unaccel_y,
1618ed6184dfSmrg                            scale, delta_angle);
1619ed6184dfSmrg}
1620ed6184dfSmrg
1621ed6184dfSmrg/**
1622ed6184dfSmrg * Post a gesture swipe event.  The driver is responsible for maintaining the
1623ed6184dfSmrg * correct event sequence (GestureSwipeBegin, GestureSwipeUpdate,
1624ed6184dfSmrg * GestureSwipeEnd).
1625ed6184dfSmrg *
1626ed6184dfSmrg * @param dev The device to post the event for
1627ed6184dfSmrg * @param type One of XI_GestureSwipeBegin, XI_GestureSwipeUpdate,
1628ed6184dfSmrg *        XI_GestureSwipeEnd
1629ed6184dfSmrg * @param num_touches The number of touches in the gesture
1630ed6184dfSmrg * @param flags Flags for this event
1631ed6184dfSmrg * @param delta_x,delta_y accelerated relative motion delta
1632ed6184dfSmrg * @param delta_unaccel_x,delta_unaccel_y unaccelerated relative motion delta
1633ed6184dfSmrg */
1634ed6184dfSmrgvoid
1635ed6184dfSmrgxf86PostGestureSwipeEvent(DeviceIntPtr dev, uint16_t type,
1636ed6184dfSmrg                          uint16_t num_touches, uint32_t flags,
1637ed6184dfSmrg                          double delta_x, double delta_y,
1638ed6184dfSmrg                          double delta_unaccel_x,
1639ed6184dfSmrg                          double delta_unaccel_y)
1640ed6184dfSmrg{
1641ed6184dfSmrg    QueueGestureSwipeEvents(dev, type, num_touches, flags, delta_x, delta_y,
1642ed6184dfSmrg                            delta_unaccel_x, delta_unaccel_y);
1643ed6184dfSmrg}
1644ed6184dfSmrg
164535c4bbdfSmrgvoid
164635c4bbdfSmrgxf86InputEnableVTProbe(void)
164735c4bbdfSmrg{
16481b5d61b8Smrg    int is_auto = 0;
164935c4bbdfSmrg    DeviceIntPtr pdev;
16501b5d61b8Smrg    PausedInputDevicePtr d, tmp;
165135c4bbdfSmrg
16521b5d61b8Smrg    xorg_list_for_each_entry_safe(d, tmp, &new_input_devices_list, node) {
16531b5d61b8Smrg        InputInfoPtr pInfo = d->pInfo;
16541b5d61b8Smrg        const char *value = xf86findOptionValue(pInfo->options, "_source");
165535c4bbdfSmrg
165635c4bbdfSmrg        is_auto = 0;
16571b5d61b8Smrg        if (value &&
16581b5d61b8Smrg            (strcmp(value, "server/hal") == 0 ||
16591b5d61b8Smrg             strcmp(value, "server/udev") == 0 ||
16601b5d61b8Smrg             strcmp(value, "server/wscons") == 0))
16611b5d61b8Smrg            is_auto = 1;
16621b5d61b8Smrg
166335c4bbdfSmrg        xf86NewInputDevice(pInfo, &pdev,
166435c4bbdfSmrg                                  (!is_auto ||
166535c4bbdfSmrg                                   (is_auto && xf86Info.autoEnableDevices)));
16661b5d61b8Smrg        xorg_list_del(&d->node);
16671b5d61b8Smrg        free(d);
166835c4bbdfSmrg    }
166935c4bbdfSmrg}
167035c4bbdfSmrg
167105b261ecSmrg/* end of xf86Xinput.c */
1672