1 /*
2 * Copyright 2007-2010 by Ping Cheng, Wacom. <pingc@wacom.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 #include <wacom-properties.h>
23
24 #include "xf86Wacom.h"
25 #include "wcmFilter.h"
26 #include <exevents.h>
27 #include <xf86_OSproc.h>
28
29 #ifndef XI_PROP_DEVICE_NODE
30 #define XI_PROP_DEVICE_NODE "Device Node"
31 #endif
32 #ifndef XI_PROP_PRODUCT_ID
33 #define XI_PROP_PRODUCT_ID "Device Product ID"
34 #endif
35
36 static void wcmBindToSerial(InputInfoPtr pInfo, unsigned int serial);
37
38 /*****************************************************************************
39 * wcmDevSwitchModeCall --
40 *****************************************************************************/
41
wcmDevSwitchModeCall(InputInfoPtr pInfo,int mode)42 int wcmDevSwitchModeCall(InputInfoPtr pInfo, int mode)
43 {
44 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
45
46 DBG(3, priv, "to mode=%d\n", mode);
47
48 /* Pad is always in absolute mode.*/
49 if (IsPad(priv))
50 return (mode == Absolute) ? Success : XI_BadMode;
51
52 if ((mode == Absolute) && !is_absolute(pInfo))
53 set_absolute(pInfo, TRUE);
54 else if ((mode == Relative) && is_absolute(pInfo))
55 set_absolute(pInfo, FALSE);
56 else if ( (mode != Absolute) && (mode != Relative))
57 {
58 DBG(10, priv, "invalid mode=%d\n", mode);
59 return XI_BadMode;
60 }
61
62 return Success;
63 }
64
65 /*****************************************************************************
66 * wcmDevSwitchMode --
67 *****************************************************************************/
68
wcmDevSwitchMode(ClientPtr client,DeviceIntPtr dev,int mode)69 int wcmDevSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode)
70 {
71 InputInfoPtr pInfo = (InputInfoPtr)dev->public.devicePrivate;
72 #ifdef DEBUG
73 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
74
75 DBG(3, priv, "dev=%p mode=%d\n",
76 (void *)dev, mode);
77 #endif
78 /* Share this call with sendAButton in wcmCommon.c */
79 return wcmDevSwitchModeCall(pInfo, mode);
80 }
81
82 static Atom prop_devnode;
83 static Atom prop_rotation;
84 static Atom prop_tablet_area;
85 static Atom prop_pressurecurve;
86 static Atom prop_serials;
87 static Atom prop_serial_binding;
88 static Atom prop_strip_buttons;
89 static Atom prop_wheel_buttons;
90 static Atom prop_proxout;
91 static Atom prop_threshold;
92 static Atom prop_suppress;
93 static Atom prop_touch;
94 static Atom prop_hardware_touch;
95 static Atom prop_gesture;
96 static Atom prop_gesture_param;
97 static Atom prop_hover;
98 static Atom prop_tooltype;
99 static Atom prop_btnactions;
100 static Atom prop_product_id;
101 static Atom prop_pressure_recal;
102 static Atom prop_panscroll_threshold;
103 #ifdef DEBUG
104 static Atom prop_debuglevels;
105 #endif
106
107 /**
108 * Calculate a user-visible pressure level from a driver-internal pressure
109 * level. Pressure settings exposed to the user assume a range of 0-2047
110 * while the driver scales everything to a range of 0-maxCurve.
111 */
wcmInternalToUserPressure(InputInfoPtr pInfo,int pressure)112 static inline int wcmInternalToUserPressure(InputInfoPtr pInfo, int pressure)
113 {
114 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
115 return pressure / (priv->maxCurve / 2048);
116 }
117
118 /**
119 * Calculate a driver-internal pressure level from a user-visible pressure
120 * level. Pressure settings exposed to the user assume a range of 0-2047
121 * while the driver scales everything to a range of 0-maxCurve.
122 */
wcmUserToInternalPressure(InputInfoPtr pInfo,int pressure)123 static inline int wcmUserToInternalPressure(InputInfoPtr pInfo, int pressure)
124 {
125 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
126 return pressure * (priv->maxCurve / 2048);
127 }
128
129 /**
130 * Resets an arbitrary Action property, given a pointer to the old
131 * handler and information about the new Action.
132 */
wcmResetAction(InputInfoPtr pInfo,const char * name,int index,Atom * handler,unsigned int (* action)[256],unsigned int (* new_action)[256],Atom prop,int nprop)133 static void wcmResetAction(InputInfoPtr pInfo, const char *name, int index,
134 Atom *handler, unsigned int (*action)[256],
135 unsigned int (*new_action)[256], Atom prop, int nprop)
136 {
137 handler[index] = MakeAtom(name, strlen(name), TRUE);
138 memset(action[index], 0, sizeof(action[index]));
139 memcpy(action[index], *new_action, sizeof(*new_action));
140 XIChangeDeviceProperty(pInfo->dev, handler[index], XA_INTEGER, 32,
141 PropModeReplace, 1, (char*)new_action, FALSE);
142 }
143
wcmResetButtonAction(InputInfoPtr pInfo,int button,int nbuttons)144 static void wcmResetButtonAction(InputInfoPtr pInfo, int button, int nbuttons)
145 {
146 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
147 unsigned int new_action[256] = {};
148 int x11_button = priv->button_default[button];
149 char name[64];
150
151 sprintf(name, "Wacom button action %d", button);
152 new_action[0] = AC_BUTTON | AC_KEYBTNPRESS | x11_button;
153 wcmResetAction(pInfo, name, button, priv->btn_actions, priv->keys, &new_action, prop_btnactions, nbuttons);
154 }
155
wcmResetStripAction(InputInfoPtr pInfo,int index)156 static void wcmResetStripAction(InputInfoPtr pInfo, int index)
157 {
158 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
159 unsigned int new_action[256] = {};
160 char name[64];
161
162 sprintf(name, "Wacom strip action %d", index);
163 new_action[0] = AC_BUTTON | AC_KEYBTNPRESS | (priv->strip_default[index]);
164 new_action[1] = AC_BUTTON | (priv->strip_default[index]);
165 wcmResetAction(pInfo, name, index, priv->strip_actions, priv->strip_keys, &new_action, prop_strip_buttons, 4);
166 }
167
wcmResetWheelAction(InputInfoPtr pInfo,int index)168 static void wcmResetWheelAction(InputInfoPtr pInfo, int index)
169 {
170 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
171 unsigned int new_action[256] = {};
172 char name[64];
173
174 sprintf(name, "Wacom wheel action %d", index);
175 new_action[0] = AC_BUTTON | AC_KEYBTNPRESS | (priv->wheel_default[index]);
176 new_action[1] = AC_BUTTON | (priv->wheel_default[index]);
177 wcmResetAction(pInfo, name, index, priv->wheel_actions, priv->wheel_keys, &new_action, prop_wheel_buttons, 6);
178 }
179
180 /**
181 * Registers a property for the input device. This function registers
182 * the property name atom, as well as creates the property itself.
183 * At creation, the property values are initialized from the 'values'
184 * array. The device property is marked as non-deletable.
185 * Initialization values are always to be provided by means of an
186 * array of 32 bit integers, regardless of 'format'
187 *
188 * @param dev Pointer to device structure
189 * @param name Name of device property
190 * @param type Type of the property
191 * @param format Format of the property (8/16/32)
192 * @param nvalues Number of values in the property
193 * @param values Pointer to 32 bit integer array of initial property values
194 * @return Atom handle of property name
195 */
InitWcmAtom(DeviceIntPtr dev,const char * name,Atom type,int format,int nvalues,int * values)196 static Atom InitWcmAtom(DeviceIntPtr dev, const char *name, Atom type, int format, int nvalues, int *values)
197 {
198 int i;
199 Atom atom;
200 uint8_t val_8[WCM_MAX_BUTTONS];
201 uint16_t val_16[WCM_MAX_BUTTONS];
202 uint32_t val_32[WCM_MAX_BUTTONS];
203 pointer converted = val_32;
204
205 for (i = 0; i < nvalues; i++)
206 {
207 switch(format)
208 {
209 case 8: val_8[i] = values[i]; break;
210 case 16: val_16[i] = values[i]; break;
211 case 32: val_32[i] = values[i]; break;
212 }
213 }
214
215 switch(format)
216 {
217 case 8: converted = val_8; break;
218 case 16: converted = val_16; break;
219 case 32: converted = val_32; break;
220 }
221
222 atom = MakeAtom(name, strlen(name), TRUE);
223 XIChangeDeviceProperty(dev, atom, type, format,
224 PropModeReplace, nvalues,
225 converted, FALSE);
226 XISetDevicePropertyDeletable(dev, atom, FALSE);
227 return atom;
228 }
229
InitWcmDeviceProperties(InputInfoPtr pInfo)230 void InitWcmDeviceProperties(InputInfoPtr pInfo)
231 {
232 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
233 WacomCommonPtr common = priv->common;
234 int values[WCM_MAX_BUTTONS];
235 int i;
236
237 DBG(10, priv, "\n");
238
239 prop_devnode = MakeAtom(XI_PROP_DEVICE_NODE, strlen(XI_PROP_DEVICE_NODE), TRUE);
240 XIChangeDeviceProperty(pInfo->dev, prop_devnode, XA_STRING, 8,
241 PropModeReplace, strlen(common->device_path),
242 common->device_path, FALSE);
243 XISetDevicePropertyDeletable(pInfo->dev, prop_devnode, FALSE);
244
245 if (!IsPad(priv)) {
246 values[0] = priv->topX;
247 values[1] = priv->topY;
248 values[2] = priv->bottomX;
249 values[3] = priv->bottomY;
250 prop_tablet_area = InitWcmAtom(pInfo->dev, WACOM_PROP_TABLET_AREA, XA_INTEGER, 32, 4, values);
251 }
252
253 values[0] = common->wcmRotate;
254 if (!IsPad(priv)) {
255 prop_rotation = InitWcmAtom(pInfo->dev, WACOM_PROP_ROTATION, XA_INTEGER, 8, 1, values);
256 }
257
258 if (IsPen(priv) || IsTouch(priv)) {
259 values[0] = priv->nPressCtrl[0];
260 values[1] = priv->nPressCtrl[1];
261 values[2] = priv->nPressCtrl[2];
262 values[3] = priv->nPressCtrl[3];
263 prop_pressurecurve = InitWcmAtom(pInfo->dev, WACOM_PROP_PRESSURECURVE, XA_INTEGER, 32, 4, values);
264 }
265
266 values[0] = common->tablet_id;
267 values[1] = priv->oldState.serial_num;
268 values[2] = priv->oldState.device_id;
269 values[3] = priv->cur_serial;
270 values[4] = priv->cur_device_id;
271 prop_serials = InitWcmAtom(pInfo->dev, WACOM_PROP_SERIALIDS, XA_INTEGER, 32, 5, values);
272
273 values[0] = priv->serial;
274 prop_serial_binding = InitWcmAtom(pInfo->dev, WACOM_PROP_SERIAL_BIND, XA_INTEGER, 32, 1, values);
275
276 if (IsTablet(priv)) {
277 values[0] = priv->wcmProxoutDist;
278 prop_proxout = InitWcmAtom(pInfo->dev, WACOM_PROP_PROXIMITY_THRESHOLD, XA_INTEGER, 32, 1, values);
279 }
280
281 values[0] = (!common->wcmMaxZ) ? 0 : common->wcmThreshold;
282 values[0] = wcmInternalToUserPressure(pInfo, values[0]);
283 prop_threshold = InitWcmAtom(pInfo->dev, WACOM_PROP_PRESSURE_THRESHOLD, XA_INTEGER, 32, 1, values);
284
285 values[0] = common->wcmSuppress;
286 values[1] = common->wcmRawSample;
287 prop_suppress = InitWcmAtom(pInfo->dev, WACOM_PROP_SAMPLE, XA_INTEGER, 32, 2, values);
288
289 values[0] = common->wcmTouch;
290 prop_touch = InitWcmAtom(pInfo->dev, WACOM_PROP_TOUCH, XA_INTEGER, 8, 1, values);
291
292 if (common->wcmHasHWTouchSwitch && IsTouch(priv)) {
293 values[0] = common->wcmHWTouchSwitchState;
294 prop_hardware_touch = InitWcmAtom(pInfo->dev, WACOM_PROP_HARDWARE_TOUCH, XA_INTEGER, 8, 1, values);
295 }
296
297 if (IsStylus(priv)) {
298 values[0] = !common->wcmTPCButton;
299 prop_hover = InitWcmAtom(pInfo->dev, WACOM_PROP_HOVER, XA_INTEGER, 8, 1, values);
300 }
301
302 values[0] = common->wcmGesture;
303 prop_gesture = InitWcmAtom(pInfo->dev, WACOM_PROP_ENABLE_GESTURE, XA_INTEGER, 8, 1, values);
304
305 values[0] = common->wcmGestureParameters.wcmZoomDistance;
306 values[1] = common->wcmGestureParameters.wcmScrollDistance;
307 values[2] = common->wcmGestureParameters.wcmTapTime;
308 prop_gesture_param = InitWcmAtom(pInfo->dev, WACOM_PROP_GESTURE_PARAMETERS, XA_INTEGER, 32, 3, values);
309
310 values[0] = MakeAtom(pInfo->type_name, strlen(pInfo->type_name), TRUE);
311 prop_tooltype = InitWcmAtom(pInfo->dev, WACOM_PROP_TOOL_TYPE, XA_ATOM, 32, 1, values);
312
313 memset(values, 0, sizeof(values));
314 prop_btnactions = InitWcmAtom(pInfo->dev, WACOM_PROP_BUTTON_ACTIONS, XA_ATOM, 32, priv->nbuttons, values);
315 for (i = 0; i < priv->nbuttons; i++)
316 wcmResetButtonAction(pInfo, i, priv->nbuttons);
317
318 if (IsPad(priv)) {
319 memset(values, 0, sizeof(values));
320 prop_strip_buttons = InitWcmAtom(pInfo->dev, WACOM_PROP_STRIPBUTTONS, XA_ATOM, 32, 4, values);
321 for (i = 0; i < 4; i++)
322 wcmResetStripAction(pInfo, i);
323 }
324
325 if (IsPad(priv) || IsCursor(priv))
326 {
327 memset(values, 0, sizeof(values));
328 prop_wheel_buttons = InitWcmAtom(pInfo->dev, WACOM_PROP_WHEELBUTTONS, XA_ATOM, 32, 6, values);
329 for (i = 0; i < 6; i++)
330 wcmResetWheelAction(pInfo, i);
331 }
332
333 if (IsStylus(priv) || IsEraser(priv)) {
334 values[0] = common->wcmPressureRecalibration;
335 prop_pressure_recal = InitWcmAtom(pInfo->dev,
336 WACOM_PROP_PRESSURE_RECAL,
337 XA_INTEGER, 8, 1, values);
338 }
339
340 values[0] = common->wcmPanscrollThreshold;
341 prop_panscroll_threshold = InitWcmAtom(pInfo->dev, WACOM_PROP_PANSCROLL_THRESHOLD, XA_INTEGER, 32, 1, values);
342
343 values[0] = common->vendor_id;
344 values[1] = common->tablet_id;
345 prop_product_id = InitWcmAtom(pInfo->dev, XI_PROP_PRODUCT_ID, XA_INTEGER, 32, 2, values);
346
347 #ifdef DEBUG
348 values[0] = priv->debugLevel;
349 values[1] = common->debugLevel;
350 prop_debuglevels = InitWcmAtom(pInfo->dev, WACOM_PROP_DEBUGLEVELS, XA_INTEGER, 8, 2, values);
351 #endif
352 }
353
354 /* Returns the offset of the property in the list given. If the property is
355 * not found, a negative error code is returned. */
wcmFindProp(Atom property,Atom * prop_list,int nprops)356 static int wcmFindProp(Atom property, Atom *prop_list, int nprops)
357 {
358 int i;
359
360 /* check all properties used for button actions */
361 for (i = 0; i < nprops; i++)
362 if (prop_list[i] == property)
363 return i;
364
365 return -BadAtom;
366 }
367
368 /**
369 * Obtain a pointer to the the handler and action list for a given Action
370 * property. This function searches the button, wheel, and strip property
371 * handler lists.
372 *
373 * @param priv The device whose handler lists should be searched
374 * @param property The Action property that should be searched for
375 * @param[out] handler Returns a pointer to the property's handler
376 * @param[out] action Returns a pointer to the property's action list
377 * @return 'true' if the property was found. Neither out parameter
378 * will be null if this is the case.
379 */
wcmFindActionHandler(WacomDevicePtr priv,Atom property,Atom ** handler,unsigned int (** action)[256])380 static BOOL wcmFindActionHandler(WacomDevicePtr priv, Atom property, Atom **handler, unsigned int (**action)[256])
381 {
382 int offset;
383
384 offset = wcmFindProp(property, priv->btn_actions, ARRAY_SIZE(priv->btn_actions));
385 if (offset >=0)
386 {
387 *handler = &priv->btn_actions[offset];
388 *action = &priv->keys[offset];
389 return TRUE;
390 }
391
392 offset = wcmFindProp(property, priv->wheel_actions, ARRAY_SIZE(priv->wheel_actions));
393 if (offset >= 0)
394 {
395 *handler = &priv->wheel_actions[offset];
396 *action = &priv->wheel_keys[offset];
397 return TRUE;
398 }
399
400 offset = wcmFindProp(property, priv->strip_actions, ARRAY_SIZE(priv->strip_actions));
401 if (offset >= 0)
402 {
403 *handler = &priv->strip_actions[offset];
404 *action = &priv->strip_keys[offset];
405 return TRUE;
406 }
407
408 return FALSE;
409 }
410
wcmCheckActionProperty(WacomDevicePtr priv,Atom property,XIPropertyValuePtr prop)411 static int wcmCheckActionProperty(WacomDevicePtr priv, Atom property, XIPropertyValuePtr prop)
412 {
413 CARD32 *data;
414 int j;
415
416 if (!property) {
417 DBG(3, priv, "ERROR: Atom is NONE\n");
418 return BadMatch;
419 }
420
421 if (prop == NULL) {
422 DBG(3, priv, "ERROR: Value is NULL\n");
423 return BadMatch;
424 }
425
426 if (prop->size >= 255) {
427 DBG(3, priv, "ERROR: Too many values (%ld > 255)\n", prop->size);
428 return BadMatch;
429 }
430
431 if (prop->format != 32) {
432 DBG(3, priv, "ERROR: Incorrect value format (%d != 32)\n", prop->format);
433 return BadMatch;
434 }
435
436 if (prop->type != XA_INTEGER) {
437 DBG(3, priv, "ERROR: Incorrect value type (%d != XA_INTEGER)\n", prop->type);
438 return BadMatch;
439 }
440
441 data = (CARD32*)prop->data;
442
443 for (j = 0; j < prop->size; j++)
444 {
445 int code = data[j] & AC_CODE;
446 int type = data[j] & AC_TYPE;
447
448 DBG(10, priv, "Index %d == %d (type: %d, code: %d)\n", j, data[j], type, code);
449
450 switch(type)
451 {
452 case AC_KEY:
453 break;
454 case AC_BUTTON:
455 if (code > WCM_MAX_X11BUTTON) {
456 DBG(3, priv, "ERROR: AC_BUTTON code too high (%d > %d)\n", code, WCM_MAX_X11BUTTON);
457 return BadValue;
458 }
459 break;
460 case AC_MODETOGGLE:
461 break;
462 case AC_PANSCROLL:
463 break;
464 default:
465 DBG(3, priv, "ERROR: Unknown command\n");
466 return BadValue;
467 }
468 }
469
470 return Success;
471 }
472
473 /**
474 * An 'Action' property (such as an element of "Wacom Button Actions")
475 * defines an action to be performed for some event. The property is
476 * validated, and then saved for later use. Both the property itself
477 * (as 'handler') and the data it references (as 'action') are saved.
478 *
479 * @param dev The device being modified
480 * @param property The Action property being set
481 * @param prop The data contained in 'property'
482 * @param checkonly 'true' if the property should only be checked for validity
483 * @param handler Pointer to the handler that must be updated
484 * @param action Pointer to the action list that must be updated
485 */
wcmSetActionProperty(DeviceIntPtr dev,Atom property,XIPropertyValuePtr prop,BOOL checkonly,Atom * handler,unsigned int (* action)[256])486 static int wcmSetActionProperty(DeviceIntPtr dev, Atom property,
487 XIPropertyValuePtr prop, BOOL checkonly,
488 Atom *handler, unsigned int (*action)[256])
489 {
490 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
491 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
492 int rc, i;
493
494 DBG(5, priv, "%s new actions for Atom %d\n", checkonly ? "Checking" : "Setting", property);
495
496 rc = wcmCheckActionProperty(priv, property, prop);
497 if (rc != Success) {
498 const char *msg = NULL;
499 switch (rc) {
500 case BadMatch: msg = "BadMatch"; break;
501 case BadValue: msg = "BadValue"; break;
502 default: msg = "UNKNOWN"; break;
503 }
504 DBG(3, priv, "Action validation failed with code %d (%s)\n", rc, msg);
505 return rc;
506 }
507
508 if (!checkonly)
509 {
510 memset(action, 0, sizeof(*action));
511 for (i = 0; i < prop->size; i++)
512 (*action)[i] = ((unsigned int*)prop->data)[i];
513 *handler = property;
514 }
515
516 return Success;
517 }
518
wcmCheckActionsProperty(DeviceIntPtr dev,Atom property,XIPropertyValuePtr prop)519 static int wcmCheckActionsProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop)
520 {
521 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
522 XIPropertyValuePtr val;
523 Atom *values = (Atom*)prop->data;
524 int i;
525
526 if (prop->format != 32 || prop->type != XA_ATOM)
527 return BadMatch;
528
529 for (i = 0; i < prop->size; i++)
530 {
531 if (!values[i])
532 continue;
533
534 if (values[i] == property || !ValidAtom(values[i]))
535 return BadValue;
536
537 if (XIGetDeviceProperty(pInfo->dev, values[i], &val) != Success)
538 return BadValue;
539 }
540
541 return Success;
542 }
543
544 /**
545 * An 'Actions' property (such as "Wacom Button Actions") stores a list of
546 * 'Action' properties that define an action to be performed. This function
547 * goes through the list of actions and saves each one.
548 *
549 * @param dev The device being modified
550 * @param property The Actions property being set
551 * @param prop The data contained in 'property'
552 * @param checkonly 'true' if the property should only be checked for validity
553 * @param size Expected number of elements in 'prop'
554 * @param handlers List of handlers that must be updated
555 * @param actions List of actions that must be updated
556 */
wcmSetActionsProperty(DeviceIntPtr dev,Atom property,XIPropertyValuePtr prop,BOOL checkonly,int size,Atom * handlers,unsigned int (* actions)[256])557 static int wcmSetActionsProperty(DeviceIntPtr dev, Atom property,
558 XIPropertyValuePtr prop, BOOL checkonly,
559 int size, Atom* handlers, unsigned int (*actions)[256])
560 {
561 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
562 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
563 int rc, i;
564
565 DBG(10, priv, "\n");
566
567 if (prop->size != size)
568 return BadValue;
569
570 rc = wcmCheckActionsProperty(dev, property, prop);
571 if (rc != Success)
572 return rc;
573
574 for (i = 0; i < prop->size; i++)
575 {
576 int index = i;
577 Atom subproperty = ((Atom*)prop->data)[i];
578 XIPropertyValuePtr subprop;
579
580 if (property == prop_btnactions)
581 { /* Driver uses physical -- not X11 -- button numbering internally */
582 if (i < 3)
583 index = i;
584 else if (i < 7)
585 continue;
586 else
587 index = i - 4;
588 }
589
590 if (subproperty == 0)
591 { /* Interpret 'None' as meaning 'reset' */
592 if (!checkonly)
593 {
594 if (property == prop_btnactions)
595 wcmResetButtonAction(pInfo, index, size);
596 else if (property == prop_strip_buttons)
597 wcmResetStripAction(pInfo, index);
598 else if (property == prop_wheel_buttons)
599 wcmResetWheelAction(pInfo, index);
600
601 if (subproperty != handlers[index])
602 subproperty = handlers[index];
603 }
604 }
605 else
606 {
607 XIGetDeviceProperty(dev, subproperty, &subprop);
608 rc = wcmSetActionProperty(dev, subproperty, subprop, checkonly, &handlers[index], &actions[index]);
609 if (rc != Success)
610 return rc;
611 }
612 }
613
614 return Success;
615 }
616
617 /**
618 * Update the rotation property for all tools on the same physical tablet as
619 * pInfo.
620 */
wcmUpdateRotationProperty(WacomDevicePtr priv)621 void wcmUpdateRotationProperty(WacomDevicePtr priv)
622 {
623 WacomCommonPtr common = priv->common;
624 WacomDevicePtr other;
625 char rotation = common->wcmRotate;
626
627 for (other = common->wcmDevices; other; other = other->next)
628 {
629 InputInfoPtr pInfo;
630 DeviceIntPtr dev;
631
632 if (other == priv)
633 continue;
634
635 pInfo = other->pInfo;
636 dev = pInfo->dev;
637
638 XIChangeDeviceProperty(dev, prop_rotation, XA_INTEGER, 8,
639 PropModeReplace, 1, &rotation,
640 TRUE);
641 }
642 }
643
644 static void
wcmSetHWTouchProperty(InputInfoPtr pInfo)645 wcmSetHWTouchProperty(InputInfoPtr pInfo)
646 {
647 WacomDevicePtr priv = pInfo->private;
648 WacomCommonPtr common = priv->common;
649 XIPropertyValuePtr prop;
650 CARD8 prop_value;
651 int rc;
652
653 rc = XIGetDeviceProperty(pInfo->dev, prop_hardware_touch, &prop);
654 if (rc != Success || prop->format != 8 || prop->size != 1)
655 {
656 xf86Msg(X_ERROR, "%s: Failed to update hardware touch state.\n",
657 pInfo->name);
658 return;
659 }
660
661 prop_value = common->wcmHWTouchSwitchState;
662 XIChangeDeviceProperty(pInfo->dev, prop_hardware_touch, XA_INTEGER,
663 prop->format, PropModeReplace,
664 prop->size, &prop_value, TRUE);
665 }
666
667 static CARD32
touchTimerFunc(OsTimerPtr timer,CARD32 now,pointer arg)668 touchTimerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
669 {
670 InputInfoPtr pInfo = arg;
671 #if !HAVE_THREADED_INPUT
672 int sigstate = xf86BlockSIGIO();
673 #endif
674
675 wcmSetHWTouchProperty(pInfo);
676
677 #if !HAVE_THREADED_INPUT
678 xf86UnblockSIGIO(sigstate);
679 #endif
680
681 return 0;
682 }
683
684 /**
685 * Update HW touch property when its state is changed by touch switch
686 */
687 void
wcmUpdateHWTouchProperty(WacomDevicePtr priv,int hw_touch)688 wcmUpdateHWTouchProperty(WacomDevicePtr priv, int hw_touch)
689 {
690 WacomCommonPtr common = priv->common;
691
692 if (hw_touch == common->wcmHWTouchSwitchState)
693 return;
694
695 common->wcmHWTouchSwitchState = hw_touch;
696
697 /* This function is called during SIGIO/InputThread. Schedule timer
698 * for property event delivery by the main thread. */
699 priv->touch_timer = TimerSet(priv->touch_timer, 0 /* reltime */,
700 1, touchTimerFunc, priv->pInfo);
701 }
702
703 /**
704 * Only allow deletion of a property if it is not being used by any of the
705 * button actions.
706 */
wcmDeleteProperty(DeviceIntPtr dev,Atom property)707 int wcmDeleteProperty(DeviceIntPtr dev, Atom property)
708 {
709 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
710 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
711 int i;
712
713 i = wcmFindProp(property, priv->btn_actions, ARRAY_SIZE(priv->btn_actions));
714 if (i < 0)
715 i = wcmFindProp(property, priv->wheel_actions,
716 ARRAY_SIZE(priv->wheel_actions));
717 if (i < 0)
718 i = wcmFindProp(property, priv->strip_actions,
719 ARRAY_SIZE(priv->strip_actions));
720
721 return (i >= 0) ? BadAccess : Success;
722 }
723
wcmSetProperty(DeviceIntPtr dev,Atom property,XIPropertyValuePtr prop,BOOL checkonly)724 int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
725 BOOL checkonly)
726 {
727 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
728 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
729 WacomCommonPtr common = priv->common;
730
731 DBG(10, priv, "\n");
732
733 if (property == prop_devnode || property == prop_product_id)
734 return BadValue; /* Read-only */
735 else if (property == prop_tablet_area)
736 {
737 INT32 *values = (INT32*)prop->data;
738
739 if (prop->size != 4 || prop->format != 32)
740 return BadValue;
741
742 if (!checkonly)
743 {
744 if ((values[0] == -1) && (values[1] == -1) &&
745 (values[2] == -1) && (values[3] == -1))
746 {
747 values[0] = priv->minX;
748 values[1] = priv->minX;
749 values[2] = priv->maxX;
750 values[3] = priv->maxY;
751 }
752
753 priv->topX = values[0];
754 priv->topY = values[1];
755 priv->bottomX = values[2];
756 priv->bottomY = values[3];
757 }
758 } else if (property == prop_pressurecurve)
759 {
760 INT32 *pcurve;
761
762 if (prop->size != 4 || prop->format != 32)
763 return BadValue;
764
765 pcurve = (INT32*)prop->data;
766
767 if (!wcmCheckPressureCurveValues(pcurve[0], pcurve[1],
768 pcurve[2], pcurve[3]))
769 return BadValue;
770
771 if (IsCursor(priv) || IsPad (priv))
772 return BadValue;
773
774 if (!checkonly)
775 wcmSetPressureCurve (priv, pcurve[0], pcurve[1],
776 pcurve[2], pcurve[3]);
777 } else if (property == prop_suppress)
778 {
779 CARD32 *values;
780
781 if (prop->size != 2 || prop->format != 32)
782 return BadValue;
783
784 values = (CARD32*)prop->data;
785
786 if (values[0] > 100)
787 return BadValue;
788
789 if ((values[1] < 1) || (values[1] > MAX_SAMPLES))
790 return BadValue;
791
792 if (!checkonly)
793 {
794 common->wcmSuppress = values[0];
795 common->wcmRawSample = values[1];
796 }
797 } else if (property == prop_rotation)
798 {
799 CARD8 value;
800 if (prop->size != 1 || prop->format != 8)
801 return BadValue;
802
803 value = *(CARD8*)prop->data;
804
805 if (value > 3)
806 return BadValue;
807
808 if (!checkonly && common->wcmRotate != value)
809 wcmRotateTablet(pInfo, value);
810
811 } else if (property == prop_serials)
812 {
813 /* This property is read-only but we need to
814 * set it at runtime. If we get here from wcmUpdateSerial,
815 * we know the serial has ben set internally already, so we
816 * can reply with success. */
817 if (prop->size == 5 && prop->format == 32)
818 if (((CARD32*)prop->data)[3] == priv->cur_serial)
819 return Success;
820
821 return BadValue; /* Read-only */
822 } else if (property == prop_serial_binding)
823 {
824 unsigned int serial;
825
826 if (prop->size != 1 || prop->format != 32)
827 return BadValue;
828
829 if (!checkonly)
830 {
831 serial = *(CARD32*)prop->data;
832 wcmBindToSerial(pInfo, serial);
833 }
834 } else if (property == prop_strip_buttons)
835 return wcmSetActionsProperty(dev, property, prop, checkonly, ARRAY_SIZE(priv->strip_actions), priv->strip_actions, priv->strip_keys);
836 else if (property == prop_wheel_buttons)
837 return wcmSetActionsProperty(dev, property, prop, checkonly, ARRAY_SIZE(priv->wheel_actions), priv->wheel_actions, priv->wheel_keys);
838 else if (property == prop_proxout)
839 {
840 CARD32 value;
841
842 if (prop->size != 1 || prop->format != 32)
843 return BadValue;
844
845 if (!IsTablet (priv))
846 return BadValue;
847
848 value = *(CARD32*)prop->data;
849
850 if (value > common->wcmMaxDist)
851 return BadValue;
852
853 if (!checkonly)
854 priv->wcmProxoutDist = value;
855 } else if (property == prop_threshold)
856 {
857 const INT32 MAXIMUM = wcmInternalToUserPressure(pInfo, priv->maxCurve);
858 INT32 value;
859
860 if (prop->size != 1 || prop->format != 32)
861 return BadValue;
862
863 value = *(INT32*)prop->data;
864
865 if (value == -1)
866 value = priv->maxCurve * DEFAULT_THRESHOLD;
867 else if ((value < 1) || (value > MAXIMUM))
868 return BadValue;
869 else
870 value = wcmUserToInternalPressure(pInfo, value);
871
872 if (!checkonly)
873 common->wcmThreshold = value;
874 } else if (property == prop_touch)
875 {
876 CARD8 *values = (CARD8*)prop->data;
877
878 if (prop->size != 1 || prop->format != 8)
879 return BadValue;
880
881 if ((values[0] != 0) && (values[0] != 1))
882 return BadValue;
883
884 if (!checkonly && common->wcmTouch != values[0])
885 common->wcmTouch = values[0];
886 } else if (property == prop_hardware_touch)
887 {
888 if (common->wcmHasHWTouchSwitch)
889 {
890 /* If we get here from wcmUpdateHWTouchProperty, we know
891 * the wcmHWTouchSwitchState has been set internally
892 * already, so we can reply with success. */
893 if (prop->size == 1 && prop->format == 8)
894 if (((CARD8*)prop->data)[0] == common->wcmHWTouchSwitchState)
895 return Success;
896 }
897
898 return BadValue; /* read-only */
899 } else if (property == prop_gesture)
900 {
901 CARD8 *values = (CARD8*)prop->data;
902
903 if (prop->size != 1 || prop->format != 8)
904 return BadValue;
905
906 if ((values[0] != 0) && (values[0] != 1))
907 return BadValue;
908
909 if (!checkonly && common->wcmGesture != values[0])
910 common->wcmGesture = values[0];
911 } else if (property == prop_gesture_param)
912 {
913 CARD32 *values;
914
915 if (prop->size != 3 || prop->format != 32)
916 return BadValue;
917
918 values = (CARD32*)prop->data;
919
920 if (!checkonly)
921 {
922 if (common->wcmGestureParameters.wcmZoomDistance != values[0])
923 common->wcmGestureParameters.wcmZoomDistance = values[0];
924 if (common->wcmGestureParameters.wcmScrollDistance != values[1])
925 common->wcmGestureParameters.wcmScrollDistance = values[1];
926 if (common->wcmGestureParameters.wcmTapTime != values[2])
927 common->wcmGestureParameters.wcmTapTime = values[2];
928 }
929 } else if (property == prop_hover)
930 {
931 CARD8 *values = (CARD8*)prop->data;
932
933 if (prop->size != 1 || prop->format != 8)
934 return BadValue;
935
936 if ((values[0] != 0) && (values[0] != 1))
937 return BadValue;
938
939 if (!IsStylus(priv))
940 return BadMatch;
941
942 if (!checkonly)
943 common->wcmTPCButton = !values[0];
944 #ifdef DEBUG
945 } else if (property == prop_debuglevels)
946 {
947 CARD8 *values;
948
949 if (prop->size != 2 || prop->format != 8)
950 return BadMatch;
951
952 values = (CARD8*)prop->data;
953 if (values[0] > 12 || values[1] > 12)
954 return BadValue;
955
956 if (!checkonly)
957 {
958 priv->debugLevel = values[0];
959 common->debugLevel = values[1];
960 }
961 #endif
962 } else if (property == prop_btnactions)
963 {
964 int nbuttons = priv->nbuttons < 4 ? priv->nbuttons : priv->nbuttons + 4;
965 return wcmSetActionsProperty(dev, property, prop, checkonly, nbuttons, priv->btn_actions, priv->keys);
966 } else if (property == prop_pressure_recal)
967 {
968 CARD8 *values = (CARD8*)prop->data;
969
970 if (prop->size != 1 || prop->format != 8)
971 return BadValue;
972
973 if ((values[0] != 0) && (values[0] != 1))
974 return BadValue;
975
976 if (!IsStylus(priv) && !IsEraser(priv))
977 return BadMatch;
978
979 if (!checkonly)
980 common->wcmPressureRecalibration = values[0];
981 } else if (property == prop_panscroll_threshold)
982 {
983 CARD32 *values = (CARD32*)prop->data;
984
985 if (prop->size != 1 || prop->format != 32)
986 return BadValue;
987
988 if (values[0] <= 0)
989 return BadValue;
990
991 if (IsTouch(priv))
992 return BadMatch;
993
994 if (!checkonly)
995 common->wcmPanscrollThreshold = values[0];
996 } else
997 {
998 Atom *handler = NULL;
999 unsigned int (*action)[256] = NULL;
1000 if (wcmFindActionHandler(priv, property, &handler, &action))
1001 return wcmSetActionProperty(dev, property, prop, checkonly, handler, action);
1002 /* backwards-compatible behavior silently ignores the not-found case */
1003 }
1004
1005 return Success;
1006 }
1007
wcmGetProperty(DeviceIntPtr dev,Atom property)1008 int wcmGetProperty (DeviceIntPtr dev, Atom property)
1009 {
1010 InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
1011 WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
1012 WacomCommonPtr common = priv->common;
1013
1014 DBG(10, priv, "\n");
1015
1016 if (property == prop_serials)
1017 {
1018 uint32_t values[5];
1019
1020 values[0] = common->tablet_id;
1021 values[1] = priv->oldState.serial_num;
1022 values[2] = priv->oldState.device_id;
1023 values[3] = priv->cur_serial;
1024 values[4] = priv->cur_device_id;
1025
1026 DBG(10, priv, "Update to serial: %d\n", priv->oldState.serial_num);
1027
1028 return XIChangeDeviceProperty(dev, property, XA_INTEGER, 32,
1029 PropModeReplace, 5,
1030 values, FALSE);
1031 }
1032 else if (property == prop_btnactions)
1033 {
1034 /* Convert the physical button representation used internally
1035 * to the X11 button representation we've historically used.
1036 * To do this, we need to skip X11 buttons 4-7 which would be
1037 * used by a scroll wheel rather than an actual button.
1038 */
1039 int nbuttons = priv->nbuttons < 4 ? priv->nbuttons : priv->nbuttons + 4;
1040 Atom x11_btn_actions[nbuttons];
1041 int i;
1042
1043 for (i = 0; i < nbuttons; i++)
1044 {
1045 if (i < 3)
1046 x11_btn_actions[i] = priv->btn_actions[i];
1047 else if (i < 7)
1048 x11_btn_actions[i] = 0;
1049 else
1050 x11_btn_actions[i] = priv->btn_actions[i-4];
1051 }
1052
1053 return XIChangeDeviceProperty(dev, property, XA_ATOM, 32,
1054 PropModeReplace, nbuttons,
1055 x11_btn_actions, FALSE);
1056 }
1057 else if (property == prop_strip_buttons)
1058 {
1059 return XIChangeDeviceProperty(dev, property, XA_ATOM, 32,
1060 PropModeReplace, ARRAY_SIZE(priv->strip_actions),
1061 priv->strip_actions, FALSE);
1062 }
1063 else if (property == prop_wheel_buttons)
1064 {
1065 return XIChangeDeviceProperty(dev, property, XA_ATOM, 32,
1066 PropModeReplace, ARRAY_SIZE(priv->wheel_actions),
1067 priv->wheel_actions, FALSE);
1068 }
1069
1070 return Success;
1071 }
1072
1073 static void
wcmSetSerialProperty(InputInfoPtr pInfo)1074 wcmSetSerialProperty(InputInfoPtr pInfo)
1075 {
1076 WacomDevicePtr priv = pInfo->private;
1077 XIPropertyValuePtr prop;
1078 CARD32 prop_value[5];
1079 int rc;
1080
1081 rc = XIGetDeviceProperty(pInfo->dev, prop_serials, &prop);
1082 if (rc != Success || prop->format != 32 || prop->size != 5)
1083 {
1084 xf86Msg(X_ERROR, "%s: Failed to update serial number.\n",
1085 pInfo->name);
1086 return;
1087 }
1088
1089 memcpy(prop_value, prop->data, sizeof(prop_value));
1090 prop_value[3] = priv->cur_serial;
1091 prop_value[4] = priv->cur_device_id;
1092
1093 XIChangeDeviceProperty(pInfo->dev, prop_serials, XA_INTEGER,
1094 prop->format, PropModeReplace,
1095 prop->size, prop_value, TRUE);
1096 }
1097
1098 static CARD32
serialTimerFunc(OsTimerPtr timer,CARD32 now,pointer arg)1099 serialTimerFunc(OsTimerPtr timer, CARD32 now, pointer arg)
1100 {
1101 InputInfoPtr pInfo = arg;
1102
1103 #if !HAVE_THREADED_INPUT
1104 int sigstate = xf86BlockSIGIO();
1105 #endif
1106
1107 wcmSetSerialProperty(pInfo);
1108
1109 #if !HAVE_THREADED_INPUT
1110 xf86UnblockSIGIO(sigstate);
1111 #endif
1112
1113 return 0;
1114 }
1115
1116 void
wcmUpdateSerial(InputInfoPtr pInfo,unsigned int serial,int id)1117 wcmUpdateSerial(InputInfoPtr pInfo, unsigned int serial, int id)
1118 {
1119 WacomDevicePtr priv = pInfo->private;
1120
1121 if (priv->cur_serial == serial && priv->cur_device_id == id)
1122 return;
1123
1124 priv->cur_serial = serial;
1125 priv->cur_device_id = id;
1126
1127 /* This function is called during SIGIO/InputThread. Schedule timer
1128 * for property event delivery by the main thread. */
1129 priv->serial_timer = TimerSet(priv->serial_timer, 0 /* reltime */,
1130 1, serialTimerFunc, pInfo);
1131 }
1132
1133 static void
wcmBindToSerial(InputInfoPtr pInfo,unsigned int serial)1134 wcmBindToSerial(InputInfoPtr pInfo, unsigned int serial)
1135 {
1136 WacomDevicePtr priv = pInfo->private;
1137
1138 priv->serial = serial;
1139
1140 }
1141
1142 /* vim: set noexpandtab tabstop=8 shiftwidth=8: */
1143