1706f2543Smrg/*
2706f2543Smrg * Copyright 1995-1999 by Frederic Lepied, France. <Lepied@XFree86.org>
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is  hereby granted without fee, provided that
6706f2543Smrg * the  above copyright   notice appear  in   all  copies and  that both  that
7706f2543Smrg * copyright  notice   and   this  permission   notice  appear  in  supporting
8706f2543Smrg * documentation, and that   the  name of  Frederic   Lepied not  be  used  in
9706f2543Smrg * advertising or publicity pertaining to distribution of the software without
10706f2543Smrg * specific,  written      prior  permission.     Frederic  Lepied   makes  no
11706f2543Smrg * representations about the suitability of this software for any purpose.  It
12706f2543Smrg * is provided "as is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * FREDERIC  LEPIED DISCLAIMS ALL   WARRANTIES WITH REGARD  TO  THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED   WARRANTIES OF MERCHANTABILITY  AND   FITNESS, IN NO
16706f2543Smrg * EVENT  SHALL FREDERIC  LEPIED BE   LIABLE   FOR ANY  SPECIAL, INDIRECT   OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA  OR PROFITS, WHETHER  IN  AN ACTION OF  CONTRACT,  NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS  ACTION, ARISING    OUT OF OR   IN  CONNECTION  WITH THE USE    OR
20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
21706f2543Smrg *
22706f2543Smrg */
23706f2543Smrg/*
24706f2543Smrg * Copyright (c) 2000-2002 by The XFree86 Project, Inc.
25706f2543Smrg *
26706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
27706f2543Smrg * copy of this software and associated documentation files (the "Software"),
28706f2543Smrg * to deal in the Software without restriction, including without limitation
29706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
30706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
31706f2543Smrg * Software is furnished to do so, subject to the following conditions:
32706f2543Smrg *
33706f2543Smrg * The above copyright notice and this permission notice shall be included in
34706f2543Smrg * all copies or substantial portions of the Software.
35706f2543Smrg *
36706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
39706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
40706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
41706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE.
42706f2543Smrg *
43706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s)
44706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote
45706f2543Smrg * the sale, use or other dealings in this Software without prior written
46706f2543Smrg * authorization from the copyright holder(s) and author(s).
47706f2543Smrg */
48706f2543Smrg
49706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
50706f2543Smrg#include <xorg-config.h>
51706f2543Smrg#endif
52706f2543Smrg
53706f2543Smrg#include <X11/Xfuncproto.h>
54706f2543Smrg#include <X11/Xmd.h>
55706f2543Smrg#include <X11/extensions/XI.h>
56706f2543Smrg#include <X11/extensions/XIproto.h>
57706f2543Smrg#include <X11/Xatom.h>
58706f2543Smrg#include "xf86.h"
59706f2543Smrg#include "xf86Priv.h"
60706f2543Smrg#include "xf86Config.h"
61706f2543Smrg#include "xf86Xinput.h"
62706f2543Smrg#include "xf86Optrec.h"
63706f2543Smrg#include "mipointer.h"
64706f2543Smrg#include "extinit.h"
65706f2543Smrg#include "loaderProcs.h"
66706f2543Smrg
67706f2543Smrg#include "exevents.h"	/* AddInputDevice */
68706f2543Smrg#include "exglobals.h"
69706f2543Smrg#include "eventstr.h"
70706f2543Smrg#include "inpututils.h"
71706f2543Smrg
72706f2543Smrg#include <string.h>     /* InputClassMatches */
73706f2543Smrg#ifdef HAVE_FNMATCH_H
74706f2543Smrg#include <fnmatch.h>
75706f2543Smrg#endif
76706f2543Smrg#ifdef HAVE_SYS_UTSNAME_H
77706f2543Smrg#include <sys/utsname.h>
78706f2543Smrg#endif
79706f2543Smrg
80706f2543Smrg#include <stdarg.h>
81706f2543Smrg#include <stdint.h>          /* for int64_t */
82706f2543Smrg
83706f2543Smrg#include "mi.h"
84706f2543Smrg
85706f2543Smrg#include <ptrveloc.h>          /* dix pointer acceleration */
86706f2543Smrg#include <xserver-properties.h>
87706f2543Smrg
88706f2543Smrg#ifdef XFreeXDGA
89706f2543Smrg#include "dgaproc.h"
90706f2543Smrg#endif
91706f2543Smrg
92706f2543Smrg#include "xkbsrv.h"
93706f2543Smrg
94706f2543Smrg/* Valuator verification macro */
95706f2543Smrg#define XI_VERIFY_VALUATORS(num_valuators)					\
96706f2543Smrg	if (num_valuators > MAX_VALUATORS) {					\
97706f2543Smrg		xf86Msg(X_ERROR, "%s: num_valuator %d is greater than"		\
98706f2543Smrg			" MAX_VALUATORS\n", __FUNCTION__, num_valuators);	\
99706f2543Smrg		return;								\
100706f2543Smrg	}
101706f2543Smrg
102706f2543SmrgEventListPtr xf86Events = NULL;
103706f2543Smrg
104706f2543Smrgstatic int
105706f2543Smrgxf86InputDevicePostInit(DeviceIntPtr dev);
106706f2543Smrg
107706f2543Smrg/**
108706f2543Smrg * Eval config and modify DeviceVelocityRec accordingly
109706f2543Smrg */
110706f2543Smrgstatic void
111706f2543SmrgProcessVelocityConfiguration(DeviceIntPtr pDev, char* devname, pointer list,
112706f2543Smrg                             DeviceVelocityPtr s)
113706f2543Smrg{
114706f2543Smrg    int tempi;
115706f2543Smrg    float tempf;
116706f2543Smrg    Atom float_prop = XIGetKnownProperty(XATOM_FLOAT);
117706f2543Smrg    Atom prop;
118706f2543Smrg
119706f2543Smrg    if(!s)
120706f2543Smrg        return;
121706f2543Smrg
122706f2543Smrg    /* common settings (available via device properties) */
123706f2543Smrg    tempf = xf86SetRealOption(list, "ConstantDeceleration", 1.0);
124706f2543Smrg    if (tempf > 1.0) {
125706f2543Smrg        xf86Msg(X_CONFIG, "%s: (accel) constant deceleration by %.1f\n",
126706f2543Smrg                devname, tempf);
127706f2543Smrg        prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
128706f2543Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
129706f2543Smrg                               PropModeReplace, 1, &tempf, FALSE);
130706f2543Smrg    }
131706f2543Smrg
132706f2543Smrg    tempf = xf86SetRealOption(list, "AdaptiveDeceleration", 1.0);
133706f2543Smrg    if (tempf > 1.0) {
134706f2543Smrg        xf86Msg(X_CONFIG, "%s: (accel) adaptive deceleration by %.1f\n",
135706f2543Smrg                devname, tempf);
136706f2543Smrg        prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
137706f2543Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
138706f2543Smrg                               PropModeReplace, 1, &tempf, FALSE);
139706f2543Smrg    }
140706f2543Smrg
141706f2543Smrg    /* select profile by number */
142706f2543Smrg    tempi = xf86SetIntOption(list, "AccelerationProfile",
143706f2543Smrg            s->statistics.profile_number);
144706f2543Smrg
145706f2543Smrg    prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
146706f2543Smrg    if (XIChangeDeviceProperty(pDev, prop, XA_INTEGER, 32,
147706f2543Smrg                               PropModeReplace, 1, &tempi, FALSE) == Success) {
148706f2543Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i\n", devname,
149706f2543Smrg                tempi);
150706f2543Smrg    } else {
151706f2543Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration profile %i is unknown\n",
152706f2543Smrg                devname, tempi);
153706f2543Smrg    }
154706f2543Smrg
155706f2543Smrg    /* set scaling */
156706f2543Smrg    tempf = xf86SetRealOption(list, "ExpectedRate", 0);
157706f2543Smrg    prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
158706f2543Smrg    if (tempf > 0) {
159706f2543Smrg        tempf = 1000.0 / tempf;
160706f2543Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
161706f2543Smrg                               PropModeReplace, 1, &tempf, FALSE);
162706f2543Smrg    } else {
163706f2543Smrg        tempf = xf86SetRealOption(list, "VelocityScale", s->corr_mul);
164706f2543Smrg        XIChangeDeviceProperty(pDev, prop, float_prop, 32,
165706f2543Smrg                               PropModeReplace, 1, &tempf, FALSE);
166706f2543Smrg    }
167706f2543Smrg
168706f2543Smrg    tempi = xf86SetIntOption(list, "VelocityTrackerCount", -1);
169706f2543Smrg    if (tempi > 1)
170706f2543Smrg	InitTrackers(s, tempi);
171706f2543Smrg
172706f2543Smrg    s->initial_range = xf86SetIntOption(list, "VelocityInitialRange",
173706f2543Smrg                                        s->initial_range);
174706f2543Smrg
175706f2543Smrg    s->max_diff = xf86SetRealOption(list, "VelocityAbsDiff", s->max_diff);
176706f2543Smrg
177706f2543Smrg    tempf = xf86SetRealOption(list, "VelocityRelDiff", -1);
178706f2543Smrg    if (tempf >= 0) {
179706f2543Smrg	xf86Msg(X_CONFIG, "%s: (accel) max rel. velocity difference: %.1f%%\n",
180706f2543Smrg	        devname, tempf*100.0);
181706f2543Smrg	s->max_rel_diff = tempf;
182706f2543Smrg    }
183706f2543Smrg
184706f2543Smrg    /*  Configure softening. If const deceleration is used, this is expected
185706f2543Smrg     *  to provide better subpixel information so we enable
186706f2543Smrg     *  softening by default only if ConstantDeceleration is not used
187706f2543Smrg     */
188706f2543Smrg    s->use_softening = xf86SetBoolOption(list, "Softening",
189706f2543Smrg                                         s->const_acceleration == 1.0);
190706f2543Smrg
191706f2543Smrg    s->average_accel = xf86SetBoolOption(list, "AccelerationProfileAveraging",
192706f2543Smrg                                         s->average_accel);
193706f2543Smrg
194706f2543Smrg    s->reset_time = xf86SetIntOption(list, "VelocityReset", s->reset_time);
195706f2543Smrg}
196706f2543Smrg
197706f2543Smrgstatic void
198706f2543SmrgApplyAccelerationSettings(DeviceIntPtr dev){
199706f2543Smrg    int scheme, i;
200706f2543Smrg    DeviceVelocityPtr pVel;
201706f2543Smrg    InputInfoPtr pInfo = (InputInfoPtr)dev->public.devicePrivate;
202706f2543Smrg    char* schemeStr;
203706f2543Smrg
204706f2543Smrg    if (dev->valuator && dev->ptrfeed) {
205706f2543Smrg	schemeStr = xf86SetStrOption(pInfo->options, "AccelerationScheme", "");
206706f2543Smrg
207706f2543Smrg	scheme = dev->valuator->accelScheme.number;
208706f2543Smrg
209706f2543Smrg	if (!xf86NameCmp(schemeStr, "predictable"))
210706f2543Smrg	    scheme = PtrAccelPredictable;
211706f2543Smrg
212706f2543Smrg	if (!xf86NameCmp(schemeStr, "lightweight"))
213706f2543Smrg	    scheme = PtrAccelLightweight;
214706f2543Smrg
215706f2543Smrg	if (!xf86NameCmp(schemeStr, "none"))
216706f2543Smrg	    scheme = PtrAccelNoOp;
217706f2543Smrg
218706f2543Smrg        /* reinit scheme if needed */
219706f2543Smrg        if (dev->valuator->accelScheme.number != scheme) {
220706f2543Smrg            if (dev->valuator->accelScheme.AccelCleanupProc) {
221706f2543Smrg                dev->valuator->accelScheme.AccelCleanupProc(dev);
222706f2543Smrg            }
223706f2543Smrg
224706f2543Smrg            if (InitPointerAccelerationScheme(dev, scheme)) {
225706f2543Smrg		xf86Msg(X_CONFIG, "%s: (accel) selected scheme %s/%i\n",
226706f2543Smrg		        pInfo->name, schemeStr, scheme);
227706f2543Smrg	    } else {
228706f2543Smrg        	xf86Msg(X_CONFIG, "%s: (accel) could not init scheme %s\n",
229706f2543Smrg		        pInfo->name, schemeStr);
230706f2543Smrg        	scheme = dev->valuator->accelScheme.number;
231706f2543Smrg            }
232706f2543Smrg        } else {
233706f2543Smrg            xf86Msg(X_CONFIG, "%s: (accel) keeping acceleration scheme %i\n",
234706f2543Smrg                    pInfo->name, scheme);
235706f2543Smrg        }
236706f2543Smrg
237706f2543Smrg        free(schemeStr);
238706f2543Smrg
239706f2543Smrg        /* process special configuration */
240706f2543Smrg        switch (scheme) {
241706f2543Smrg            case PtrAccelPredictable:
242706f2543Smrg                pVel = GetDevicePredictableAccelData(dev);
243706f2543Smrg                ProcessVelocityConfiguration (dev, pInfo->name, pInfo->options,
244706f2543Smrg                                              pVel);
245706f2543Smrg                break;
246706f2543Smrg        }
247706f2543Smrg
248706f2543Smrg        i = xf86SetIntOption(pInfo->options, "AccelerationNumerator",
249706f2543Smrg                             dev->ptrfeed->ctrl.num);
250706f2543Smrg        if (i >= 0)
251706f2543Smrg            dev->ptrfeed->ctrl.num = i;
252706f2543Smrg
253706f2543Smrg        i = xf86SetIntOption(pInfo->options, "AccelerationDenominator",
254706f2543Smrg                             dev->ptrfeed->ctrl.den);
255706f2543Smrg        if (i > 0)
256706f2543Smrg            dev->ptrfeed->ctrl.den = i;
257706f2543Smrg
258706f2543Smrg        i = xf86SetIntOption(pInfo->options, "AccelerationThreshold",
259706f2543Smrg                             dev->ptrfeed->ctrl.threshold);
260706f2543Smrg        if (i >= 0)
261706f2543Smrg            dev->ptrfeed->ctrl.threshold = i;
262706f2543Smrg
263706f2543Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration factor: %.3f\n",
264706f2543Smrg                            pInfo->name, ((float)dev->ptrfeed->ctrl.num)/
265706f2543Smrg                                         ((float)dev->ptrfeed->ctrl.den));
266706f2543Smrg        xf86Msg(X_CONFIG, "%s: (accel) acceleration threshold: %i\n",
267706f2543Smrg                pInfo->name, dev->ptrfeed->ctrl.threshold);
268706f2543Smrg    }
269706f2543Smrg}
270706f2543Smrg
271706f2543Smrg/***********************************************************************
272706f2543Smrg *
273706f2543Smrg * xf86ProcessCommonOptions --
274706f2543Smrg *
275706f2543Smrg *	Process global options.
276706f2543Smrg *
277706f2543Smrg ***********************************************************************
278706f2543Smrg */
279706f2543Smrgvoid
280706f2543Smrgxf86ProcessCommonOptions(InputInfoPtr pInfo,
281706f2543Smrg                         pointer	list)
282706f2543Smrg{
283706f2543Smrg    if (xf86SetBoolOption(list, "Floating", 0) ||
284706f2543Smrg        !xf86SetBoolOption(list, "AlwaysCore", 1) ||
285706f2543Smrg        !xf86SetBoolOption(list, "SendCoreEvents", 1) ||
286706f2543Smrg        !xf86SetBoolOption(list, "CorePointer", 1) ||
287706f2543Smrg        !xf86SetBoolOption(list, "CoreKeyboard", 1)) {
288706f2543Smrg        xf86Msg(X_CONFIG, "%s: doesn't report core events\n", pInfo->name);
289706f2543Smrg    } else {
290706f2543Smrg        pInfo->flags |= XI86_ALWAYS_CORE;
291706f2543Smrg        xf86Msg(X_CONFIG, "%s: always reports core events\n", pInfo->name);
292706f2543Smrg    }
293706f2543Smrg}
294706f2543Smrg
295706f2543Smrg/***********************************************************************
296706f2543Smrg *
297706f2543Smrg * xf86ActivateDevice --
298706f2543Smrg *
299706f2543Smrg *	Initialize an input device.
300706f2543Smrg *
301706f2543Smrg * Returns TRUE on success, or FALSE otherwise.
302706f2543Smrg ***********************************************************************
303706f2543Smrg */
304706f2543Smrgstatic DeviceIntPtr
305706f2543Smrgxf86ActivateDevice(InputInfoPtr pInfo)
306706f2543Smrg{
307706f2543Smrg    DeviceIntPtr	dev;
308706f2543Smrg    Atom		atom;
309706f2543Smrg
310706f2543Smrg    dev = AddInputDevice(serverClient, pInfo->device_control, TRUE);
311706f2543Smrg
312706f2543Smrg    if (dev == NULL)
313706f2543Smrg    {
314706f2543Smrg        xf86Msg(X_ERROR, "Too many input devices. Ignoring %s\n",
315706f2543Smrg                pInfo->name);
316706f2543Smrg        pInfo->dev = NULL;
317706f2543Smrg        return NULL;
318706f2543Smrg    }
319706f2543Smrg
320706f2543Smrg    atom = MakeAtom(pInfo->type_name, strlen(pInfo->type_name), TRUE);
321706f2543Smrg    AssignTypeAndName(dev, atom, pInfo->name);
322706f2543Smrg    dev->public.devicePrivate = pInfo;
323706f2543Smrg    pInfo->dev = dev;
324706f2543Smrg
325706f2543Smrg    dev->coreEvents = pInfo->flags & XI86_ALWAYS_CORE;
326706f2543Smrg    dev->type = SLAVE;
327706f2543Smrg    dev->spriteInfo->spriteOwner = FALSE;
328706f2543Smrg
329706f2543Smrg    dev->config_info = xf86SetStrOption(pInfo->options, "config_info", NULL);
330706f2543Smrg
331706f2543Smrg    if (serverGeneration == 1)
332706f2543Smrg        xf86Msg(X_INFO, "XINPUT: Adding extended input device \"%s\" (type: %s)\n",
333706f2543Smrg                pInfo->name, pInfo->type_name);
334706f2543Smrg
335706f2543Smrg    return dev;
336706f2543Smrg}
337706f2543Smrg
338706f2543Smrg/****************************************************************************
339706f2543Smrg *
340706f2543Smrg * Caller:	ProcXSetDeviceMode
341706f2543Smrg *
342706f2543Smrg * Change the mode of an extension device.
343706f2543Smrg * This function is used to change the mode of a device from reporting
344706f2543Smrg * relative motion to reporting absolute positional information, and
345706f2543Smrg * vice versa.
346706f2543Smrg * The default implementation below is that no such devices are supported.
347706f2543Smrg *
348706f2543Smrg ***********************************************************************
349706f2543Smrg */
350706f2543Smrg
351706f2543Smrgint
352706f2543SmrgSetDeviceMode (ClientPtr client, DeviceIntPtr dev, int mode)
353706f2543Smrg{
354706f2543Smrg  InputInfoPtr        pInfo = (InputInfoPtr)dev->public.devicePrivate;
355706f2543Smrg
356706f2543Smrg  if (pInfo->switch_mode) {
357706f2543Smrg    return (*pInfo->switch_mode)(client, dev, mode);
358706f2543Smrg  }
359706f2543Smrg  else
360706f2543Smrg    return BadMatch;
361706f2543Smrg}
362706f2543Smrg
363706f2543Smrg
364706f2543Smrg/***********************************************************************
365706f2543Smrg *
366706f2543Smrg * Caller:	ProcXSetDeviceValuators
367706f2543Smrg *
368706f2543Smrg * Set the value of valuators on an extension input device.
369706f2543Smrg * This function is used to set the initial value of valuators on
370706f2543Smrg * those input devices that are capable of reporting either relative
371706f2543Smrg * motion or an absolute position, and allow an initial position to be set.
372706f2543Smrg * The default implementation below is that no such devices are supported.
373706f2543Smrg *
374706f2543Smrg ***********************************************************************
375706f2543Smrg */
376706f2543Smrg
377706f2543Smrgint
378706f2543SmrgSetDeviceValuators (ClientPtr client, DeviceIntPtr dev, int *valuators,
379706f2543Smrg                    int first_valuator, int num_valuators)
380706f2543Smrg{
381706f2543Smrg    InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
382706f2543Smrg
383706f2543Smrg    if (pInfo->set_device_valuators)
384706f2543Smrg	return (*pInfo->set_device_valuators)(pInfo, valuators, first_valuator,
385706f2543Smrg					      num_valuators);
386706f2543Smrg
387706f2543Smrg    return BadMatch;
388706f2543Smrg}
389706f2543Smrg
390706f2543Smrg
391706f2543Smrg/***********************************************************************
392706f2543Smrg *
393706f2543Smrg * Caller:	ProcXChangeDeviceControl
394706f2543Smrg *
395706f2543Smrg * Change the specified device controls on an extension input device.
396706f2543Smrg *
397706f2543Smrg ***********************************************************************
398706f2543Smrg */
399706f2543Smrg
400706f2543Smrgint
401706f2543SmrgChangeDeviceControl (ClientPtr client, DeviceIntPtr dev, xDeviceCtl *control)
402706f2543Smrg{
403706f2543Smrg  InputInfoPtr        pInfo = (InputInfoPtr)dev->public.devicePrivate;
404706f2543Smrg
405706f2543Smrg  if (!pInfo->control_proc) {
406706f2543Smrg      switch (control->control) {
407706f2543Smrg      case DEVICE_CORE:
408706f2543Smrg          return BadMatch;
409706f2543Smrg      case DEVICE_RESOLUTION:
410706f2543Smrg      case DEVICE_ABS_CALIB:
411706f2543Smrg      case DEVICE_ABS_AREA:
412706f2543Smrg      case DEVICE_ENABLE:
413706f2543Smrg        return Success;
414706f2543Smrg      default:
415706f2543Smrg        return BadMatch;
416706f2543Smrg      }
417706f2543Smrg  }
418706f2543Smrg  else {
419706f2543Smrg      return (*pInfo->control_proc)(pInfo, control);
420706f2543Smrg  }
421706f2543Smrg}
422706f2543Smrg
423706f2543Smrg/*
424706f2543Smrg * Get the operating system name from uname and store it statically to avoid
425706f2543Smrg * repeating the system call each time MatchOS is checked.
426706f2543Smrg */
427706f2543Smrgstatic const char *
428706f2543SmrgHostOS(void)
429706f2543Smrg{
430706f2543Smrg#ifdef HAVE_SYS_UTSNAME_H
431706f2543Smrg    struct utsname name;
432706f2543Smrg    static char host_os[sizeof(name.sysname)] = "";
433706f2543Smrg
434706f2543Smrg    if (*host_os == '\0') {
435706f2543Smrg        if (uname(&name) >= 0)
436706f2543Smrg            strcpy(host_os, name.sysname);
437706f2543Smrg        else {
438706f2543Smrg            strncpy(host_os, "unknown", sizeof(host_os));
439706f2543Smrg            host_os[sizeof(host_os)-1] = '\0';
440706f2543Smrg        }
441706f2543Smrg    }
442706f2543Smrg    return host_os;
443706f2543Smrg#else
444706f2543Smrg    return "";
445706f2543Smrg#endif
446706f2543Smrg}
447706f2543Smrg
448706f2543Smrgstatic int
449706f2543Smrgmatch_substring(const char *attr, const char *pattern)
450706f2543Smrg{
451706f2543Smrg    return (strstr(attr, pattern)) ? 0 : -1;
452706f2543Smrg}
453706f2543Smrg
454706f2543Smrg#ifdef HAVE_FNMATCH_H
455706f2543Smrgstatic int
456706f2543Smrgmatch_pattern(const char *attr, const char *pattern)
457706f2543Smrg{
458706f2543Smrg    return fnmatch(pattern, attr, 0);
459706f2543Smrg}
460706f2543Smrg#else
461706f2543Smrg#define match_pattern match_substring
462706f2543Smrg#endif
463706f2543Smrg
464706f2543Smrg#ifdef HAVE_FNMATCH_H
465706f2543Smrgstatic int
466706f2543Smrgmatch_path_pattern(const char *attr, const char *pattern)
467706f2543Smrg{
468706f2543Smrg    return fnmatch(pattern, attr, FNM_PATHNAME);
469706f2543Smrg}
470706f2543Smrg#else
471706f2543Smrg#define match_path_pattern match_substring
472706f2543Smrg#endif
473706f2543Smrg
474706f2543Smrg/*
475706f2543Smrg * Match an attribute against a list of NULL terminated arrays of patterns.
476706f2543Smrg * If a pattern in each list entry is matched, return TRUE.
477706f2543Smrg */
478706f2543Smrgstatic Bool
479706f2543SmrgMatchAttrToken(const char *attr, struct list *patterns,
480706f2543Smrg               int (*compare)(const char *attr, const char *pattern))
481706f2543Smrg{
482706f2543Smrg    const xf86MatchGroup *group;
483706f2543Smrg
484706f2543Smrg    /* If there are no patterns, accept the match */
485706f2543Smrg    if (list_is_empty(patterns))
486706f2543Smrg        return TRUE;
487706f2543Smrg
488706f2543Smrg    /* If there are patterns but no attribute, reject the match */
489706f2543Smrg    if (!attr)
490706f2543Smrg        return FALSE;
491706f2543Smrg
492706f2543Smrg    /*
493706f2543Smrg     * Otherwise, iterate the list of patterns ensuring each entry has a
494706f2543Smrg     * match. Each list entry is a separate Match line of the same type.
495706f2543Smrg     */
496706f2543Smrg    list_for_each_entry(group, patterns, entry) {
497706f2543Smrg        char * const *cur;
498706f2543Smrg        Bool match = FALSE;
499706f2543Smrg
500706f2543Smrg        for (cur = group->values; *cur; cur++)
501706f2543Smrg            if ((*compare)(attr, *cur) == 0) {
502706f2543Smrg                match = TRUE;
503706f2543Smrg                break;
504706f2543Smrg            }
505706f2543Smrg        if (!match)
506706f2543Smrg            return FALSE;
507706f2543Smrg    }
508706f2543Smrg
509706f2543Smrg    /* All the entries in the list matched the attribute */
510706f2543Smrg    return TRUE;
511706f2543Smrg}
512706f2543Smrg
513706f2543Smrg/*
514706f2543Smrg * Classes without any Match statements match all devices. Otherwise, all
515706f2543Smrg * statements must match.
516706f2543Smrg */
517706f2543Smrgstatic Bool
518706f2543SmrgInputClassMatches(const XF86ConfInputClassPtr iclass, const InputInfoPtr idev,
519706f2543Smrg                  const InputAttributes *attrs)
520706f2543Smrg{
521706f2543Smrg    /* MatchProduct substring */
522706f2543Smrg    if (!MatchAttrToken(attrs->product, &iclass->match_product, match_substring))
523706f2543Smrg        return FALSE;
524706f2543Smrg
525706f2543Smrg    /* MatchVendor substring */
526706f2543Smrg    if (!MatchAttrToken(attrs->vendor, &iclass->match_vendor, match_substring))
527706f2543Smrg        return FALSE;
528706f2543Smrg
529706f2543Smrg    /* MatchDevicePath pattern */
530706f2543Smrg    if (!MatchAttrToken(attrs->device, &iclass->match_device, match_path_pattern))
531706f2543Smrg        return FALSE;
532706f2543Smrg
533706f2543Smrg    /* MatchOS case-insensitive string */
534706f2543Smrg    if (!MatchAttrToken(HostOS(), &iclass->match_os, strcasecmp))
535706f2543Smrg        return FALSE;
536706f2543Smrg
537706f2543Smrg    /* MatchPnPID pattern */
538706f2543Smrg    if (!MatchAttrToken(attrs->pnp_id, &iclass->match_pnpid, match_pattern))
539706f2543Smrg        return FALSE;
540706f2543Smrg
541706f2543Smrg    /* MatchUSBID pattern */
542706f2543Smrg    if (!MatchAttrToken(attrs->usb_id, &iclass->match_usbid, match_pattern))
543706f2543Smrg        return FALSE;
544706f2543Smrg
545706f2543Smrg    /* MatchDriver string */
546706f2543Smrg    if (!MatchAttrToken(idev->driver, &iclass->match_driver, strcmp))
547706f2543Smrg        return FALSE;
548706f2543Smrg
549706f2543Smrg    /*
550706f2543Smrg     * MatchTag string
551706f2543Smrg     * See if any of the device's tags match any of the MatchTag tokens.
552706f2543Smrg     */
553706f2543Smrg    if (!list_is_empty(&iclass->match_tag)) {
554706f2543Smrg        char * const *tag;
555706f2543Smrg        Bool match;
556706f2543Smrg
557706f2543Smrg        if (!attrs->tags)
558706f2543Smrg            return FALSE;
559706f2543Smrg        for (tag = attrs->tags, match = FALSE; *tag; tag++) {
560706f2543Smrg            if (MatchAttrToken(*tag, &iclass->match_tag, strcmp)) {
561706f2543Smrg                match = TRUE;
562706f2543Smrg                break;
563706f2543Smrg            }
564706f2543Smrg        }
565706f2543Smrg        if (!match)
566706f2543Smrg            return FALSE;
567706f2543Smrg    }
568706f2543Smrg
569706f2543Smrg    /* MatchIs* booleans */
570706f2543Smrg    if (iclass->is_keyboard.set &&
571706f2543Smrg        iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD))
572706f2543Smrg        return FALSE;
573706f2543Smrg    if (iclass->is_pointer.set &&
574706f2543Smrg        iclass->is_pointer.val != !!(attrs->flags & ATTR_POINTER))
575706f2543Smrg        return FALSE;
576706f2543Smrg    if (iclass->is_joystick.set &&
577706f2543Smrg        iclass->is_joystick.val != !!(attrs->flags & ATTR_JOYSTICK))
578706f2543Smrg        return FALSE;
579706f2543Smrg    if (iclass->is_tablet.set &&
580706f2543Smrg        iclass->is_tablet.val != !!(attrs->flags & ATTR_TABLET))
581706f2543Smrg        return FALSE;
582706f2543Smrg    if (iclass->is_touchpad.set &&
583706f2543Smrg        iclass->is_touchpad.val != !!(attrs->flags & ATTR_TOUCHPAD))
584706f2543Smrg        return FALSE;
585706f2543Smrg    if (iclass->is_touchscreen.set &&
586706f2543Smrg        iclass->is_touchscreen.val != !!(attrs->flags & ATTR_TOUCHSCREEN))
587706f2543Smrg        return FALSE;
588706f2543Smrg
589706f2543Smrg    return TRUE;
590706f2543Smrg}
591706f2543Smrg
592706f2543Smrg/*
593706f2543Smrg * Merge in any InputClass configurations. Options in each InputClass
594706f2543Smrg * section have more priority than the original device configuration as
595706f2543Smrg * well as any previous InputClass sections.
596706f2543Smrg */
597706f2543Smrgstatic int
598706f2543SmrgMergeInputClasses(const InputInfoPtr idev, const InputAttributes *attrs)
599706f2543Smrg{
600706f2543Smrg    XF86ConfInputClassPtr cl;
601706f2543Smrg    XF86OptionPtr classopts;
602706f2543Smrg
603706f2543Smrg    for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
604706f2543Smrg        if (!InputClassMatches(cl, idev, attrs))
605706f2543Smrg            continue;
606706f2543Smrg
607706f2543Smrg        /* Collect class options and driver settings */
608706f2543Smrg        classopts = xf86optionListDup(cl->option_lst);
609706f2543Smrg        if (cl->driver) {
610706f2543Smrg            free(idev->driver);
611706f2543Smrg            idev->driver = xstrdup(cl->driver);
612706f2543Smrg            if (!idev->driver) {
613706f2543Smrg                xf86Msg(X_ERROR, "Failed to allocate memory while merging "
614706f2543Smrg                        "InputClass configuration");
615706f2543Smrg                return BadAlloc;
616706f2543Smrg            }
617706f2543Smrg            classopts = xf86ReplaceStrOption(classopts, "driver",
618706f2543Smrg                                             idev->driver);
619706f2543Smrg        }
620706f2543Smrg
621706f2543Smrg        /* Apply options to device with InputClass settings preferred. */
622706f2543Smrg        xf86Msg(X_CONFIG, "%s: Applying InputClass \"%s\"\n",
623706f2543Smrg                idev->name, cl->identifier);
624706f2543Smrg        idev->options = xf86optionListMerge(idev->options, classopts);
625706f2543Smrg    }
626706f2543Smrg
627706f2543Smrg    return Success;
628706f2543Smrg}
629706f2543Smrg
630706f2543Smrg/*
631706f2543Smrg * Iterate the list of classes and look for Option "Ignore". Return the
632706f2543Smrg * value of the last matching class and holler when returning TRUE.
633706f2543Smrg */
634706f2543Smrgstatic Bool
635706f2543SmrgIgnoreInputClass(const InputInfoPtr idev, const InputAttributes *attrs)
636706f2543Smrg{
637706f2543Smrg    XF86ConfInputClassPtr cl;
638706f2543Smrg    Bool ignore = FALSE;
639706f2543Smrg    const char *ignore_class;
640706f2543Smrg
641706f2543Smrg    for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
642706f2543Smrg        if (!InputClassMatches(cl, idev, attrs))
643706f2543Smrg            continue;
644706f2543Smrg        if (xf86findOption(cl->option_lst, "Ignore")) {
645706f2543Smrg            ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
646706f2543Smrg            ignore_class = cl->identifier;
647706f2543Smrg        }
648706f2543Smrg    }
649706f2543Smrg
650706f2543Smrg    if (ignore)
651706f2543Smrg        xf86Msg(X_CONFIG, "%s: Ignoring device from InputClass \"%s\"\n",
652706f2543Smrg                idev->name, ignore_class);
653706f2543Smrg    return ignore;
654706f2543Smrg}
655706f2543Smrg
656706f2543SmrgInputInfoPtr
657706f2543Smrgxf86AllocateInput(void)
658706f2543Smrg{
659706f2543Smrg    InputInfoPtr pInfo;
660706f2543Smrg
661706f2543Smrg    pInfo = calloc(sizeof(*pInfo), 1);
662706f2543Smrg    if (!pInfo)
663706f2543Smrg        return NULL;
664706f2543Smrg
665706f2543Smrg    pInfo->fd = -1;
666706f2543Smrg    pInfo->type_name = "UNKNOWN";
667706f2543Smrg
668706f2543Smrg    return pInfo;
669706f2543Smrg}
670706f2543Smrg
671706f2543Smrg/* Append InputInfoRec to the tail of xf86InputDevs. */
672706f2543Smrgstatic void
673706f2543Smrgxf86AddInput(InputDriverPtr drv, InputInfoPtr pInfo)
674706f2543Smrg{
675706f2543Smrg    InputInfoPtr *prev = NULL;
676706f2543Smrg
677706f2543Smrg    pInfo->drv = drv;
678706f2543Smrg    pInfo->module = DuplicateModule(drv->module, NULL);
679706f2543Smrg
680706f2543Smrg    for (prev = &xf86InputDevs; *prev; prev = &(*prev)->next)
681706f2543Smrg        ;
682706f2543Smrg
683706f2543Smrg    *prev = pInfo;
684706f2543Smrg    pInfo->next = NULL;
685706f2543Smrg
686706f2543Smrg    xf86CollectInputOptions(pInfo, (const char**)drv->default_options);
687706f2543Smrg    xf86OptionListReport(pInfo->options);
688706f2543Smrg    xf86ProcessCommonOptions(pInfo, pInfo->options);
689706f2543Smrg}
690706f2543Smrg
691706f2543Smrg/*
692706f2543Smrg * Remove an entry from xf86InputDevs and free all the device's information.
693706f2543Smrg */
694706f2543Smrgvoid
695706f2543Smrgxf86DeleteInput(InputInfoPtr pInp, int flags)
696706f2543Smrg{
697706f2543Smrg    /* First check if the inputdev is valid. */
698706f2543Smrg    if (pInp == NULL)
699706f2543Smrg	return;
700706f2543Smrg
701706f2543Smrg    if (pInp->module)
702706f2543Smrg	UnloadModule(pInp->module);
703706f2543Smrg
704706f2543Smrg    /* This should *really* be handled in drv->UnInit(dev) call instead, but
705706f2543Smrg     * if the driver forgets about it make sure we free it or at least crash
706706f2543Smrg     * with flying colors */
707706f2543Smrg    free(pInp->private);
708706f2543Smrg
709706f2543Smrg    FreeInputAttributes(pInp->attrs);
710706f2543Smrg
711706f2543Smrg    /* Remove the entry from the list. */
712706f2543Smrg    if (pInp == xf86InputDevs)
713706f2543Smrg	xf86InputDevs = pInp->next;
714706f2543Smrg    else {
715706f2543Smrg	InputInfoPtr p = xf86InputDevs;
716706f2543Smrg	while (p && p->next != pInp)
717706f2543Smrg	    p = p->next;
718706f2543Smrg	if (p)
719706f2543Smrg	    p->next = pInp->next;
720706f2543Smrg	/* Else the entry wasn't in the xf86InputDevs list (ignore this). */
721706f2543Smrg    }
722706f2543Smrg
723706f2543Smrg    free(pInp->driver);
724706f2543Smrg    free(pInp->name);
725706f2543Smrg    xf86optionListFree(pInp->options);
726706f2543Smrg    free(pInp);
727706f2543Smrg}
728706f2543Smrg
729706f2543Smrg/*
730706f2543Smrg * Apply backend-specific initialization. Invoked after ActiveteDevice(),
731706f2543Smrg * i.e. after the driver successfully completed DEVICE_INIT and the device
732706f2543Smrg * is advertised.
733706f2543Smrg * @param dev the device
734706f2543Smrg * @return Success or an error code
735706f2543Smrg */
736706f2543Smrgstatic int
737706f2543Smrgxf86InputDevicePostInit(DeviceIntPtr dev) {
738706f2543Smrg    ApplyAccelerationSettings(dev);
739706f2543Smrg    return Success;
740706f2543Smrg}
741706f2543Smrg
742706f2543Smrg/**
743706f2543Smrg * Create a new input device, activate and enable it.
744706f2543Smrg *
745706f2543Smrg * Possible return codes:
746706f2543Smrg *    BadName .. a bad driver name was supplied.
747706f2543Smrg *    BadImplementation ... The driver does not have a PreInit function. This
748706f2543Smrg *                          is a driver bug.
749706f2543Smrg *    BadMatch .. device initialization failed.
750706f2543Smrg *    BadAlloc .. too many input devices
751706f2543Smrg *
752706f2543Smrg * @param idev The device, already set up with identifier, driver, and the
753706f2543Smrg * options.
754706f2543Smrg * @param pdev Pointer to the new device, if Success was reported.
755706f2543Smrg * @param enable Enable the device after activating it.
756706f2543Smrg *
757706f2543Smrg * @return Success or an error code
758706f2543Smrg */
759706f2543Smrg_X_INTERNAL int
760706f2543Smrgxf86NewInputDevice(InputInfoPtr pInfo, DeviceIntPtr *pdev, BOOL enable)
761706f2543Smrg{
762706f2543Smrg    InputDriverPtr drv = NULL;
763706f2543Smrg    DeviceIntPtr dev = NULL;
764706f2543Smrg    int rval;
765706f2543Smrg
766706f2543Smrg    /* Memory leak for every attached device if we don't
767706f2543Smrg     * test if the module is already loaded first */
768706f2543Smrg    drv = xf86LookupInputDriver(pInfo->driver);
769706f2543Smrg    if (!drv)
770706f2543Smrg        if (xf86LoadOneModule(pInfo->driver, NULL))
771706f2543Smrg            drv = xf86LookupInputDriver(pInfo->driver);
772706f2543Smrg    if (!drv) {
773706f2543Smrg        xf86Msg(X_ERROR, "No input driver matching `%s'\n", pInfo->driver);
774706f2543Smrg        rval = BadName;
775706f2543Smrg        goto unwind;
776706f2543Smrg    }
777706f2543Smrg
778706f2543Smrg    xf86Msg(X_INFO, "Using input driver '%s' for '%s'\n", drv->driverName, pInfo->name);
779706f2543Smrg
780706f2543Smrg    if (!drv->PreInit) {
781706f2543Smrg        xf86Msg(X_ERROR,
782706f2543Smrg                "Input driver `%s' has no PreInit function (ignoring)\n",
783706f2543Smrg                drv->driverName);
784706f2543Smrg        rval = BadImplementation;
785706f2543Smrg        goto unwind;
786706f2543Smrg    }
787706f2543Smrg
788706f2543Smrg    xf86AddInput(drv, pInfo);
789706f2543Smrg
790706f2543Smrg    rval = drv->PreInit(drv, pInfo, 0);
791706f2543Smrg
792706f2543Smrg    if (rval != Success) {
793706f2543Smrg        xf86Msg(X_ERROR, "PreInit returned %d for \"%s\"\n", rval, pInfo->name);
794706f2543Smrg        goto unwind;
795706f2543Smrg    }
796706f2543Smrg
797706f2543Smrg    if (!(dev = xf86ActivateDevice(pInfo)))
798706f2543Smrg    {
799706f2543Smrg        rval = BadAlloc;
800706f2543Smrg        goto unwind;
801706f2543Smrg    }
802706f2543Smrg
803706f2543Smrg    rval = ActivateDevice(dev, TRUE);
804706f2543Smrg    if (rval != Success)
805706f2543Smrg    {
806706f2543Smrg        xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", pInfo->name);
807706f2543Smrg        RemoveDevice(dev, TRUE);
808706f2543Smrg        goto unwind;
809706f2543Smrg    }
810706f2543Smrg
811706f2543Smrg    rval = xf86InputDevicePostInit(dev);
812706f2543Smrg    if (rval != Success)
813706f2543Smrg    {
814706f2543Smrg	xf86Msg(X_ERROR, "Couldn't post-init device \"%s\"\n", pInfo->name);
815706f2543Smrg	RemoveDevice(dev, TRUE);
816706f2543Smrg	goto unwind;
817706f2543Smrg    }
818706f2543Smrg
819706f2543Smrg    /* Enable it if it's properly initialised and we're currently in the VT */
820706f2543Smrg    if (enable && dev->inited && dev->startup && xf86Screens[0]->vtSema)
821706f2543Smrg    {
822706f2543Smrg        OsBlockSignals();
823706f2543Smrg        EnableDevice(dev, TRUE);
824706f2543Smrg        if (!dev->enabled)
825706f2543Smrg        {
826706f2543Smrg            OsReleaseSignals();
827706f2543Smrg            xf86Msg(X_ERROR, "Couldn't init device \"%s\"\n", pInfo->name);
828706f2543Smrg            RemoveDevice(dev, TRUE);
829706f2543Smrg            rval = BadMatch;
830706f2543Smrg            goto unwind;
831706f2543Smrg        }
832706f2543Smrg        /* send enter/leave event, update sprite window */
833706f2543Smrg        CheckMotion(NULL, dev);
834706f2543Smrg        OsReleaseSignals();
835706f2543Smrg    }
836706f2543Smrg
837706f2543Smrg    *pdev = dev;
838706f2543Smrg    return Success;
839706f2543Smrg
840706f2543Smrgunwind:
841706f2543Smrg    if(pInfo) {
842706f2543Smrg        if(drv && drv->UnInit)
843706f2543Smrg            drv->UnInit(drv, pInfo, 0);
844706f2543Smrg        else
845706f2543Smrg            xf86DeleteInput(pInfo, 0);
846706f2543Smrg    }
847706f2543Smrg    return rval;
848706f2543Smrg}
849706f2543Smrg
850706f2543Smrgint
851706f2543SmrgNewInputDeviceRequest (InputOption *options, InputAttributes *attrs,
852706f2543Smrg                       DeviceIntPtr *pdev)
853706f2543Smrg{
854706f2543Smrg    InputInfoPtr pInfo = NULL;
855706f2543Smrg    InputOption *option = NULL;
856706f2543Smrg    int rval = Success;
857706f2543Smrg    int is_auto = 0;
858706f2543Smrg
859706f2543Smrg    pInfo = xf86AllocateInput();
860706f2543Smrg    if (!pInfo)
861706f2543Smrg        return BadAlloc;
862706f2543Smrg
863706f2543Smrg    for (option = options; option; option = option->next) {
864706f2543Smrg        if (strcasecmp(option->key, "driver") == 0) {
865706f2543Smrg            if (pInfo->driver) {
866706f2543Smrg                rval = BadRequest;
867706f2543Smrg                goto unwind;
868706f2543Smrg            }
869706f2543Smrg            pInfo->driver = xstrdup(option->value);
870706f2543Smrg            if (!pInfo->driver) {
871706f2543Smrg                rval = BadAlloc;
872706f2543Smrg                goto unwind;
873706f2543Smrg            }
874706f2543Smrg        }
875706f2543Smrg
876706f2543Smrg        if (strcasecmp(option->key, "name") == 0 ||
877706f2543Smrg            strcasecmp(option->key, "identifier") == 0) {
878706f2543Smrg            if (pInfo->name) {
879706f2543Smrg                rval = BadRequest;
880706f2543Smrg                goto unwind;
881706f2543Smrg            }
882706f2543Smrg            pInfo->name = xstrdup(option->value);
883706f2543Smrg            if (!pInfo->name) {
884706f2543Smrg                rval = BadAlloc;
885706f2543Smrg                goto unwind;
886706f2543Smrg            }
887706f2543Smrg        }
888706f2543Smrg
889706f2543Smrg        if (strcmp(option->key, "_source") == 0 &&
890706f2543Smrg            (strcmp(option->value, "server/hal") == 0 ||
891706f2543Smrg             strcmp(option->value, "server/udev") == 0)) {
892706f2543Smrg            is_auto = 1;
893706f2543Smrg            if (!xf86Info.autoAddDevices) {
894706f2543Smrg                rval = BadMatch;
895706f2543Smrg                goto unwind;
896706f2543Smrg            }
897706f2543Smrg        }
898706f2543Smrg    }
899706f2543Smrg
900706f2543Smrg    for (option = options; option; option = option->next) {
901706f2543Smrg        /* Steal option key/value strings from the provided list.
902706f2543Smrg         * We need those strings, the InputOption list doesn't. */
903706f2543Smrg        pInfo->options = xf86addNewOption(pInfo->options,
904706f2543Smrg                                               option->key, option->value);
905706f2543Smrg        option->key = NULL;
906706f2543Smrg        option->value = NULL;
907706f2543Smrg    }
908706f2543Smrg
909706f2543Smrg    /* Apply InputClass settings */
910706f2543Smrg    if (attrs) {
911706f2543Smrg        if (IgnoreInputClass(pInfo, attrs)) {
912706f2543Smrg            rval = BadIDChoice;
913706f2543Smrg            goto unwind;
914706f2543Smrg        }
915706f2543Smrg
916706f2543Smrg        rval = MergeInputClasses(pInfo, attrs);
917706f2543Smrg        if (rval != Success)
918706f2543Smrg            goto unwind;
919706f2543Smrg
920706f2543Smrg        pInfo->attrs = DuplicateInputAttributes(attrs);
921706f2543Smrg    }
922706f2543Smrg
923706f2543Smrg    if (!pInfo->name) {
924706f2543Smrg        xf86Msg(X_INFO, "No identifier specified, ignoring this device.\n");
925706f2543Smrg        rval = BadRequest;
926706f2543Smrg        goto unwind;
927706f2543Smrg    }
928706f2543Smrg
929706f2543Smrg    if (!pInfo->driver) {
930706f2543Smrg        xf86Msg(X_INFO, "No input driver specified, ignoring this device.\n");
931706f2543Smrg        xf86Msg(X_INFO, "This device may have been added with another device file.\n");
932706f2543Smrg        rval = BadRequest;
933706f2543Smrg        goto unwind;
934706f2543Smrg    }
935706f2543Smrg
936706f2543Smrg    rval = xf86NewInputDevice(pInfo, pdev,
937706f2543Smrg                (!is_auto || (is_auto && xf86Info.autoEnableDevices)));
938706f2543Smrg
939706f2543Smrg    return rval;
940706f2543Smrg
941706f2543Smrgunwind:
942706f2543Smrg    if (is_auto && !xf86Info.autoAddDevices)
943706f2543Smrg        xf86Msg(X_INFO, "AutoAddDevices is off - not adding device.\n");
944706f2543Smrg    xf86DeleteInput(pInfo, 0);
945706f2543Smrg    return rval;
946706f2543Smrg}
947706f2543Smrg
948706f2543Smrgvoid
949706f2543SmrgDeleteInputDeviceRequest(DeviceIntPtr pDev)
950706f2543Smrg{
951706f2543Smrg    InputInfoPtr pInfo = (InputInfoPtr) pDev->public.devicePrivate;
952706f2543Smrg    InputDriverPtr drv = NULL;
953706f2543Smrg    Bool isMaster = IsMaster(pDev);
954706f2543Smrg
955706f2543Smrg    if (pInfo) /* need to get these before RemoveDevice */
956706f2543Smrg        drv = pInfo->drv;
957706f2543Smrg
958706f2543Smrg    OsBlockSignals();
959706f2543Smrg    RemoveDevice(pDev, TRUE);
960706f2543Smrg
961706f2543Smrg    if (!isMaster && pInfo != NULL)
962706f2543Smrg    {
963706f2543Smrg        if(drv->UnInit)
964706f2543Smrg            drv->UnInit(drv, pInfo, 0);
965706f2543Smrg        else
966706f2543Smrg            xf86DeleteInput(pInfo, 0);
967706f2543Smrg    }
968706f2543Smrg    OsReleaseSignals();
969706f2543Smrg}
970706f2543Smrg
971706f2543Smrg/*
972706f2543Smrg * convenient functions to post events
973706f2543Smrg */
974706f2543Smrg
975706f2543Smrgvoid
976706f2543Smrgxf86PostMotionEvent(DeviceIntPtr	device,
977706f2543Smrg                    int			is_absolute,
978706f2543Smrg                    int			first_valuator,
979706f2543Smrg                    int			num_valuators,
980706f2543Smrg                    ...)
981706f2543Smrg{
982706f2543Smrg    va_list var;
983706f2543Smrg    int i = 0;
984706f2543Smrg    ValuatorMask mask;
985706f2543Smrg
986706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
987706f2543Smrg
988706f2543Smrg    valuator_mask_zero(&mask);
989706f2543Smrg    va_start(var, num_valuators);
990706f2543Smrg    for (i = 0; i < num_valuators; i++)
991706f2543Smrg        valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
992706f2543Smrg    va_end(var);
993706f2543Smrg
994706f2543Smrg    xf86PostMotionEventM(device, is_absolute, &mask);
995706f2543Smrg}
996706f2543Smrg
997706f2543Smrgvoid
998706f2543Smrgxf86PostMotionEventP(DeviceIntPtr	device,
999706f2543Smrg                    int			is_absolute,
1000706f2543Smrg                    int			first_valuator,
1001706f2543Smrg                    int			num_valuators,
1002706f2543Smrg                    const int		*valuators)
1003706f2543Smrg{
1004706f2543Smrg    ValuatorMask mask;
1005706f2543Smrg
1006706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
1007706f2543Smrg
1008706f2543Smrg    valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1009706f2543Smrg    xf86PostMotionEventM(device, is_absolute, &mask);
1010706f2543Smrg}
1011706f2543Smrg
1012706f2543Smrgvoid
1013706f2543Smrgxf86PostMotionEventM(DeviceIntPtr	device,
1014706f2543Smrg                     int		is_absolute,
1015706f2543Smrg                     const ValuatorMask	*mask)
1016706f2543Smrg{
1017706f2543Smrg    int i = 0, nevents = 0;
1018706f2543Smrg    DeviceEvent *event;
1019706f2543Smrg    int flags = 0;
1020706f2543Smrg
1021706f2543Smrg    if (valuator_mask_num_valuators(mask) > 0)
1022706f2543Smrg    {
1023706f2543Smrg        if (is_absolute)
1024706f2543Smrg            flags = POINTER_ABSOLUTE;
1025706f2543Smrg        else
1026706f2543Smrg            flags = POINTER_RELATIVE | POINTER_ACCELERATE;
1027706f2543Smrg    }
1028706f2543Smrg
1029706f2543Smrg#if XFreeXDGA
1030706f2543Smrg    /* The evdev driver may not always send all axes across. */
1031706f2543Smrg    if (valuator_mask_isset(mask, 0) ||
1032706f2543Smrg        valuator_mask_isset(mask, 1))
1033706f2543Smrg        if (miPointerGetScreen(device)) {
1034706f2543Smrg            int index = miPointerGetScreen(device)->myNum;
1035706f2543Smrg            int dx = 0, dy = 0;
1036706f2543Smrg
1037706f2543Smrg            if (valuator_mask_isset(mask, 0))
1038706f2543Smrg            {
1039706f2543Smrg                dx = valuator_mask_get(mask, 0);
1040706f2543Smrg                if (is_absolute)
1041706f2543Smrg                    dx -= device->last.valuators[0];
1042706f2543Smrg            }
1043706f2543Smrg
1044706f2543Smrg            if (valuator_mask_isset(mask, 1))
1045706f2543Smrg            {
1046706f2543Smrg                dy = valuator_mask_get(mask, 1);
1047706f2543Smrg                if (is_absolute)
1048706f2543Smrg                    dy -= device->last.valuators[1];
1049706f2543Smrg            }
1050706f2543Smrg
1051706f2543Smrg            if (DGAStealMotionEvent(device, index, dx, dy))
1052706f2543Smrg                return;
1053706f2543Smrg        }
1054706f2543Smrg#endif
1055706f2543Smrg
1056706f2543Smrg    nevents = GetPointerEvents(xf86Events, device, MotionNotify, 0, flags, mask);
1057706f2543Smrg
1058706f2543Smrg    for (i = 0; i < nevents; i++) {
1059706f2543Smrg        event = (DeviceEvent*)((xf86Events + i)->event);
1060706f2543Smrg        mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event));
1061706f2543Smrg    }
1062706f2543Smrg}
1063706f2543Smrg
1064706f2543Smrgvoid
1065706f2543Smrgxf86PostProximityEvent(DeviceIntPtr	device,
1066706f2543Smrg                       int		is_in,
1067706f2543Smrg                       int		first_valuator,
1068706f2543Smrg                       int		num_valuators,
1069706f2543Smrg                       ...)
1070706f2543Smrg{
1071706f2543Smrg    va_list var;
1072706f2543Smrg    int i;
1073706f2543Smrg    ValuatorMask mask;
1074706f2543Smrg
1075706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
1076706f2543Smrg
1077706f2543Smrg    valuator_mask_zero(&mask);
1078706f2543Smrg    va_start(var, num_valuators);
1079706f2543Smrg    for (i = 0; i < num_valuators; i++)
1080706f2543Smrg        valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
1081706f2543Smrg    va_end(var);
1082706f2543Smrg
1083706f2543Smrg    xf86PostProximityEventM(device, is_in, &mask);
1084706f2543Smrg}
1085706f2543Smrg
1086706f2543Smrgvoid
1087706f2543Smrgxf86PostProximityEventP(DeviceIntPtr	device,
1088706f2543Smrg                        int		is_in,
1089706f2543Smrg                        int		first_valuator,
1090706f2543Smrg                        int		num_valuators,
1091706f2543Smrg                        const int	*valuators)
1092706f2543Smrg{
1093706f2543Smrg    ValuatorMask mask;
1094706f2543Smrg
1095706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
1096706f2543Smrg
1097706f2543Smrg    valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1098706f2543Smrg    xf86PostProximityEventM(device, is_in, &mask);
1099706f2543Smrg}
1100706f2543Smrg
1101706f2543Smrgvoid
1102706f2543Smrgxf86PostProximityEventM(DeviceIntPtr	device,
1103706f2543Smrg                        int		is_in,
1104706f2543Smrg                        const ValuatorMask *mask)
1105706f2543Smrg{
1106706f2543Smrg    int i, nevents;
1107706f2543Smrg
1108706f2543Smrg    nevents = GetProximityEvents(xf86Events, device,
1109706f2543Smrg                                 is_in ? ProximityIn : ProximityOut, mask);
1110706f2543Smrg    for (i = 0; i < nevents; i++)
1111706f2543Smrg        mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event));
1112706f2543Smrg
1113706f2543Smrg}
1114706f2543Smrg
1115706f2543Smrgvoid
1116706f2543Smrgxf86PostButtonEvent(DeviceIntPtr	device,
1117706f2543Smrg                    int			is_absolute,
1118706f2543Smrg                    int			button,
1119706f2543Smrg                    int			is_down,
1120706f2543Smrg                    int			first_valuator,
1121706f2543Smrg                    int			num_valuators,
1122706f2543Smrg                    ...)
1123706f2543Smrg{
1124706f2543Smrg    va_list var;
1125706f2543Smrg    ValuatorMask mask;
1126706f2543Smrg    int i = 0;
1127706f2543Smrg
1128706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
1129706f2543Smrg
1130706f2543Smrg    valuator_mask_zero(&mask);
1131706f2543Smrg
1132706f2543Smrg    va_start(var, num_valuators);
1133706f2543Smrg    for (i = 0; i < num_valuators; i++)
1134706f2543Smrg        valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
1135706f2543Smrg    va_end(var);
1136706f2543Smrg
1137706f2543Smrg    xf86PostButtonEventM(device, is_absolute, button, is_down, &mask);
1138706f2543Smrg}
1139706f2543Smrg
1140706f2543Smrgvoid
1141706f2543Smrgxf86PostButtonEventP(DeviceIntPtr	device,
1142706f2543Smrg                     int		is_absolute,
1143706f2543Smrg                     int		button,
1144706f2543Smrg                     int		is_down,
1145706f2543Smrg                     int		first_valuator,
1146706f2543Smrg                     int		num_valuators,
1147706f2543Smrg                     const int		*valuators)
1148706f2543Smrg{
1149706f2543Smrg    ValuatorMask mask;
1150706f2543Smrg
1151706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
1152706f2543Smrg
1153706f2543Smrg    valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1154706f2543Smrg    xf86PostButtonEventM(device, is_absolute, button, is_down, &mask);
1155706f2543Smrg}
1156706f2543Smrg
1157706f2543Smrgvoid
1158706f2543Smrgxf86PostButtonEventM(DeviceIntPtr	device,
1159706f2543Smrg                     int		is_absolute,
1160706f2543Smrg                     int		button,
1161706f2543Smrg                     int		is_down,
1162706f2543Smrg                     const ValuatorMask	*mask)
1163706f2543Smrg{
1164706f2543Smrg    int i = 0, nevents = 0;
1165706f2543Smrg    int flags = 0;
1166706f2543Smrg
1167706f2543Smrg    if (valuator_mask_num_valuators(mask) > 0)
1168706f2543Smrg    {
1169706f2543Smrg        if (is_absolute)
1170706f2543Smrg            flags = POINTER_ABSOLUTE;
1171706f2543Smrg        else
1172706f2543Smrg            flags = POINTER_RELATIVE | POINTER_ACCELERATE;
1173706f2543Smrg    }
1174706f2543Smrg
1175706f2543Smrg#if XFreeXDGA
1176706f2543Smrg    if (miPointerGetScreen(device)) {
1177706f2543Smrg        int index = miPointerGetScreen(device)->myNum;
1178706f2543Smrg
1179706f2543Smrg        if (DGAStealButtonEvent(device, index, button, is_down))
1180706f2543Smrg            return;
1181706f2543Smrg    }
1182706f2543Smrg#endif
1183706f2543Smrg
1184706f2543Smrg    nevents = GetPointerEvents(xf86Events, device,
1185706f2543Smrg                               is_down ? ButtonPress : ButtonRelease, button,
1186706f2543Smrg                               flags, mask);
1187706f2543Smrg
1188706f2543Smrg    for (i = 0; i < nevents; i++)
1189706f2543Smrg        mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event));
1190706f2543Smrg
1191706f2543Smrg}
1192706f2543Smrg
1193706f2543Smrgvoid
1194706f2543Smrgxf86PostKeyEvent(DeviceIntPtr	device,
1195706f2543Smrg                 unsigned int	key_code,
1196706f2543Smrg                 int		is_down,
1197706f2543Smrg                 int		is_absolute,
1198706f2543Smrg                 int		first_valuator,
1199706f2543Smrg                 int		num_valuators,
1200706f2543Smrg                 ...)
1201706f2543Smrg{
1202706f2543Smrg    va_list var;
1203706f2543Smrg    int i = 0;
1204706f2543Smrg    ValuatorMask mask;
1205706f2543Smrg
1206706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
1207706f2543Smrg
1208706f2543Smrg    valuator_mask_zero(&mask);
1209706f2543Smrg
1210706f2543Smrg    va_start(var, num_valuators);
1211706f2543Smrg    for (i = 0; i < num_valuators; i++)
1212706f2543Smrg        valuator_mask_set(&mask, first_valuator + i, va_arg(var, int));
1213706f2543Smrg    va_end(var);
1214706f2543Smrg
1215706f2543Smrg    xf86PostKeyEventM(device, key_code, is_down, is_absolute, &mask);
1216706f2543Smrg}
1217706f2543Smrg
1218706f2543Smrgvoid
1219706f2543Smrgxf86PostKeyEventP(DeviceIntPtr	device,
1220706f2543Smrg                  unsigned int	key_code,
1221706f2543Smrg                  int		is_down,
1222706f2543Smrg                  int		is_absolute,
1223706f2543Smrg                  int		first_valuator,
1224706f2543Smrg                  int		num_valuators,
1225706f2543Smrg                  const int	*valuators)
1226706f2543Smrg{
1227706f2543Smrg    ValuatorMask mask;
1228706f2543Smrg
1229706f2543Smrg    XI_VERIFY_VALUATORS(num_valuators);
1230706f2543Smrg
1231706f2543Smrg    valuator_mask_set_range(&mask, first_valuator, num_valuators, valuators);
1232706f2543Smrg    xf86PostKeyEventM(device, key_code, is_down, is_absolute, &mask);
1233706f2543Smrg}
1234706f2543Smrg
1235706f2543Smrgvoid
1236706f2543Smrgxf86PostKeyEventM(DeviceIntPtr	device,
1237706f2543Smrg                  unsigned int	key_code,
1238706f2543Smrg                  int		is_down,
1239706f2543Smrg                  int		is_absolute,
1240706f2543Smrg                  const ValuatorMask *mask)
1241706f2543Smrg{
1242706f2543Smrg    int i = 0, nevents = 0;
1243706f2543Smrg
1244706f2543Smrg#if XFreeXDGA
1245706f2543Smrg    DeviceIntPtr pointer;
1246706f2543Smrg
1247706f2543Smrg    /* Some pointers send key events, paired device is wrong then. */
1248706f2543Smrg    pointer = IsPointerDevice(device) ? device : GetPairedDevice(device);
1249706f2543Smrg    if (miPointerGetScreen(pointer)) {
1250706f2543Smrg        int index = miPointerGetScreen(pointer)->myNum;
1251706f2543Smrg
1252706f2543Smrg        if (DGAStealKeyEvent(device, index, key_code, is_down))
1253706f2543Smrg            return;
1254706f2543Smrg    }
1255706f2543Smrg#endif
1256706f2543Smrg
1257706f2543Smrg    if (is_absolute) {
1258706f2543Smrg        nevents = GetKeyboardValuatorEvents(xf86Events, device,
1259706f2543Smrg                                            is_down ? KeyPress : KeyRelease,
1260706f2543Smrg                                            key_code, mask);
1261706f2543Smrg    }
1262706f2543Smrg    else {
1263706f2543Smrg        nevents = GetKeyboardEvents(xf86Events, device,
1264706f2543Smrg                                    is_down ? KeyPress : KeyRelease,
1265706f2543Smrg                                    key_code);
1266706f2543Smrg    }
1267706f2543Smrg
1268706f2543Smrg    for (i = 0; i < nevents; i++)
1269706f2543Smrg        mieqEnqueue(device, (InternalEvent*)((xf86Events + i)->event));
1270706f2543Smrg}
1271706f2543Smrg
1272706f2543Smrgvoid
1273706f2543Smrgxf86PostKeyboardEvent(DeviceIntPtr      device,
1274706f2543Smrg                      unsigned int      key_code,
1275706f2543Smrg                      int               is_down)
1276706f2543Smrg{
1277706f2543Smrg    ValuatorMask mask;
1278706f2543Smrg
1279706f2543Smrg    valuator_mask_zero(&mask);
1280706f2543Smrg    xf86PostKeyEventM(device, key_code, is_down, 0, &mask);
1281706f2543Smrg}
1282706f2543Smrg
1283706f2543SmrgInputInfoPtr
1284706f2543Smrgxf86FirstLocalDevice(void)
1285706f2543Smrg{
1286706f2543Smrg    return xf86InputDevs;
1287706f2543Smrg}
1288706f2543Smrg
1289706f2543Smrg/*
1290706f2543Smrg * Cx     - raw data from touch screen
1291706f2543Smrg * to_max - scaled highest dimension
1292706f2543Smrg *          (remember, this is of rows - 1 because of 0 origin)
1293706f2543Smrg * to_min  - scaled lowest dimension
1294706f2543Smrg * from_max - highest raw value from touch screen calibration
1295706f2543Smrg * from_min  - lowest raw value from touch screen calibration
1296706f2543Smrg *
1297706f2543Smrg * This function is the same for X or Y coordinates.
1298706f2543Smrg * You may have to reverse the high and low values to compensate for
1299706f2543Smrg * different orgins on the touch screen vs X.
1300706f2543Smrg *
1301706f2543Smrg * e.g. to scale from device coordinates into screen coordinates, call
1302706f2543Smrg * xf86ScaleAxis(x, 0, screen_width, dev_min, dev_max);
1303706f2543Smrg */
1304706f2543Smrg
1305706f2543Smrgint
1306706f2543Smrgxf86ScaleAxis(int	Cx,
1307706f2543Smrg              int	to_max,
1308706f2543Smrg              int	to_min,
1309706f2543Smrg              int	from_max,
1310706f2543Smrg              int	from_min )
1311706f2543Smrg{
1312706f2543Smrg    int X;
1313706f2543Smrg    int64_t to_width = to_max - to_min;
1314706f2543Smrg    int64_t from_width = from_max - from_min;
1315706f2543Smrg
1316706f2543Smrg    if (from_width) {
1317706f2543Smrg	X = (int)(((to_width * (Cx - from_min)) / from_width) + to_min);
1318706f2543Smrg    }
1319706f2543Smrg    else {
1320706f2543Smrg	X = 0;
1321706f2543Smrg	ErrorF ("Divide by Zero in xf86ScaleAxis\n");
1322706f2543Smrg    }
1323706f2543Smrg
1324706f2543Smrg    if (X > to_max)
1325706f2543Smrg	X = to_max;
1326706f2543Smrg    if (X < to_min)
1327706f2543Smrg	X = to_min;
1328706f2543Smrg
1329706f2543Smrg    return X;
1330706f2543Smrg}
1331706f2543Smrg
1332706f2543Smrg/*
1333706f2543Smrg * This function checks the given screen against the current screen and
1334706f2543Smrg * makes changes if appropriate. It should be called from an XInput driver's
1335706f2543Smrg * ReadInput function before any events are posted, if the device is screen
1336706f2543Smrg * specific like a touch screen.
1337706f2543Smrg */
1338706f2543Smrgvoid
1339706f2543Smrgxf86XInputSetScreen(InputInfoPtr	pInfo,
1340706f2543Smrg		    int			screen_number,
1341706f2543Smrg		    int			x,
1342706f2543Smrg		    int			y)
1343706f2543Smrg{
1344706f2543Smrg    if (miPointerGetScreen(pInfo->dev) !=
1345706f2543Smrg          screenInfo.screens[screen_number]) {
1346706f2543Smrg	miPointerSetScreen(pInfo->dev, screen_number, x, y);
1347706f2543Smrg    }
1348706f2543Smrg}
1349706f2543Smrg
1350706f2543Smrg
1351706f2543Smrgvoid
1352706f2543Smrgxf86InitValuatorAxisStruct(DeviceIntPtr dev, int axnum, Atom label, int minval, int maxval,
1353706f2543Smrg			   int resolution, int min_res, int max_res, int mode)
1354706f2543Smrg{
1355706f2543Smrg    if (!dev || !dev->valuator)
1356706f2543Smrg        return;
1357706f2543Smrg
1358706f2543Smrg    InitValuatorAxisStruct(dev, axnum, label, minval, maxval, resolution, min_res,
1359706f2543Smrg			   max_res, mode);
1360706f2543Smrg}
1361706f2543Smrg
1362706f2543Smrg/*
1363706f2543Smrg * Set the valuator values to be in synch with dix/event.c
1364706f2543Smrg * DefineInitialRootWindow().
1365706f2543Smrg */
1366706f2543Smrgvoid
1367706f2543Smrgxf86InitValuatorDefaults(DeviceIntPtr dev, int axnum)
1368706f2543Smrg{
1369706f2543Smrg    if (axnum == 0) {
1370706f2543Smrg	dev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2;
1371706f2543Smrg        dev->last.valuators[0] = dev->valuator->axisVal[0];
1372706f2543Smrg    }
1373706f2543Smrg    else if (axnum == 1) {
1374706f2543Smrg	dev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2;
1375706f2543Smrg        dev->last.valuators[1] = dev->valuator->axisVal[1];
1376706f2543Smrg    }
1377706f2543Smrg}
1378706f2543Smrg
1379706f2543Smrg
1380706f2543Smrg/**
1381706f2543Smrg * Deactivate a device. Call this function from the driver if you receive a
1382706f2543Smrg * read error or something else that spoils your day.
1383706f2543Smrg * Device will be moved to the off_devices list, but it will still be there
1384706f2543Smrg * until you really clean up after it.
1385706f2543Smrg * Notifies the client about an inactive device.
1386706f2543Smrg *
1387706f2543Smrg * @param panic True if device is unrecoverable and needs to be removed.
1388706f2543Smrg */
1389706f2543Smrgvoid
1390706f2543Smrgxf86DisableDevice(DeviceIntPtr dev, Bool panic)
1391706f2543Smrg{
1392706f2543Smrg    if(!panic)
1393706f2543Smrg    {
1394706f2543Smrg        DisableDevice(dev, TRUE);
1395706f2543Smrg    } else
1396706f2543Smrg    {
1397706f2543Smrg        SendDevicePresenceEvent(dev->id, DeviceUnrecoverable);
1398706f2543Smrg        DeleteInputDeviceRequest(dev);
1399706f2543Smrg    }
1400706f2543Smrg}
1401706f2543Smrg
1402706f2543Smrg/**
1403706f2543Smrg * Reactivate a device. Call this function from the driver if you just found
1404706f2543Smrg * out that the read error wasn't quite that bad after all.
1405706f2543Smrg * Device will be re-activated, and an event sent to the client.
1406706f2543Smrg */
1407706f2543Smrgvoid
1408706f2543Smrgxf86EnableDevice(DeviceIntPtr dev)
1409706f2543Smrg{
1410706f2543Smrg    EnableDevice(dev, TRUE);
1411706f2543Smrg}
1412706f2543Smrg
1413706f2543Smrg/* end of xf86Xinput.c */
1414