1 /*
2 * Copyright 2009 - 2013 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
23 #include "xf86Wacom.h"
24 #include "wcmFilter.h"
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28
29 /* wcmCheckSource - Check if there is another source defined this device
30 * before or not: don't add the tool by hal/udev if user has defined at least
31 * one tool for the device in xorg.conf. One device can have multiple tools
32 * with the same type to individualize tools with serial number or areas */
wcmCheckSource(InputInfoPtr pInfo,dev_t min_maj)33 static Bool wcmCheckSource(InputInfoPtr pInfo, dev_t min_maj)
34 {
35 int match = 0;
36 InputInfoPtr pDevices = xf86FirstLocalDevice();
37 char* fsource = xf86CheckStrOption(pInfo->options, "_source", "");
38
39 for (; !match && pDevices != NULL; pDevices = pDevices->next)
40 {
41 char* device = xf86CheckStrOption(pDevices->options, "Device", NULL);
42
43 /* device can be NULL on some distros */
44 if (!device)
45 continue;
46
47 free(device);
48
49 if (!strstr(pDevices->drv->driverName, "wacom"))
50 continue;
51
52 if (pInfo != pDevices)
53 {
54 WacomCommonPtr pCommon = ((WacomDevicePtr)pDevices->private)->common;
55 char* psource = xf86CheckStrOption(pDevices->options, "_source", "");
56
57 if (pCommon->min_maj &&
58 pCommon->min_maj == min_maj)
59 {
60 /* only add the new tool if the matching major/minor
61 * was from the same source */
62 if (strcmp(fsource, psource))
63 match = 1;
64 }
65 free(psource);
66 }
67 }
68 free(fsource);
69
70 if (match)
71 xf86Msg(X_WARNING, "%s: device file already in use by %s. "
72 "Ignoring.\n", pInfo->name, pDevices->name);
73 return match;
74 }
75
76 /* check if the device has been added.
77 * Open the device and check it's major/minor, then compare this with every
78 * other wacom device listed in the config. If they share the same
79 * major/minor and the same source/type, fail.
80 * This is to detect duplicate devices if a device was added once through
81 * the xorg.conf and is then hotplugged through the server backend (HAL,
82 * udev). In this case, the hotplugged one fails.
83 */
wcmIsDuplicate(const char * device,InputInfoPtr pInfo)84 int wcmIsDuplicate(const char* device, InputInfoPtr pInfo)
85 {
86 struct stat st;
87 int isInUse = 0;
88 char* lsource = xf86CheckStrOption(pInfo->options, "_source", NULL);
89
90 /* always allow xorg.conf defined tools to be added */
91 if (!lsource || !strlen(lsource)) goto ret;
92
93 if (stat(device, &st) == -1)
94 {
95 /* can not access major/minor to check device duplication */
96 xf86Msg(X_ERROR, "%s: stat failed (%s). cannot check for duplicates.\n",
97 pInfo->name, strerror(errno));
98
99 /* older systems don't support the required ioctl. let it pass */
100 goto ret;
101 }
102
103 if (st.st_rdev)
104 {
105 /* device matches with another added port */
106 if (wcmCheckSource(pInfo, st.st_rdev))
107 {
108 isInUse = 3;
109 goto ret;
110 }
111 }
112 else
113 {
114 /* major/minor can never be 0, right? */
115 xf86Msg(X_ERROR, "%s: device opened with a major/minor of 0. "
116 "Something was wrong.\n", pInfo->name);
117 isInUse = 4;
118 }
119 ret:
120 free(lsource);
121 return isInUse;
122 }
123
124 static struct
125 {
126 const char* type;
127 uint16_t tool[3]; /* tool array is terminated by 0 */
128 } wcmType [] =
129 {
130 { "stylus", { BTN_TOOL_PEN, 0 } },
131 { "eraser", { BTN_TOOL_RUBBER, 0 } },
132 { "cursor", { BTN_TOOL_MOUSE, 0 } },
133 { "touch", { BTN_TOOL_DOUBLETAP, BTN_TOOL_FINGER, 0 } },
134 { "pad", { BTN_FORWARD, BTN_0, 0 } }
135 };
136
137 /* validate tool type for device/product */
wcmIsAValidType(InputInfoPtr pInfo,const char * type)138 Bool wcmIsAValidType(InputInfoPtr pInfo, const char* type)
139 {
140 int j, k, ret = FALSE;
141 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
142 WacomCommonPtr common = priv->common;
143 char* dsource;
144
145 if (!type)
146 {
147 xf86Msg(X_ERROR, "%s: No type specified\n", pInfo->name);
148 return FALSE;
149 }
150
151 dsource = xf86CheckStrOption(pInfo->options, "_source", NULL);
152
153 /* walkthrough all types */
154 for (j = 0; j < ARRAY_SIZE(wcmType); j++)
155 {
156 if (!strcmp(wcmType[j].type, type))
157 {
158 for (k = 0; wcmType[j].tool[k] && !ret; k++)
159 {
160 if (ISBITSET (common->wcmKeys, wcmType[j].tool[k]))
161 {
162 ret = TRUE;
163
164 /* non GENERIC devices use BTN_TOOL_FINGER for pad */
165 if (common->wcmProtocolLevel != WCM_PROTOCOL_GENERIC)
166 {
167 if (!strcmp(type, "touch") &&
168 wcmType[j].tool[k] == BTN_TOOL_FINGER)
169 ret = FALSE;
170 }
171 }
172 else if (!dsource || !strlen(dsource)) /* an user defined type */
173 {
174 /* assume it is a valid type */
175 SETBIT(common->wcmKeys, wcmType[j].tool[k]);
176 ret = TRUE;
177 }
178 }
179 }
180 }
181
182 if (!ret)
183 xf86Msg(X_ERROR, "%s: Invalid type '%s' for this device.\n",
184 pInfo->name, type);
185
186 free(dsource);
187 return ret;
188 }
189
190 /* Choose valid types according to device ID. */
wcmDeviceTypeKeys(InputInfoPtr pInfo)191 int wcmDeviceTypeKeys(InputInfoPtr pInfo)
192 {
193 int ret = 1;
194 WacomDevicePtr priv = pInfo->private;
195 WacomCommonPtr common = priv->common;
196
197 priv->common->tablet_id = common->wcmDevCls->ProbeKeys(pInfo);
198
199 switch (priv->common->tablet_id)
200 {
201 case 0xF8: /* Cintiq 24HDT */
202 case 0xF4: /* Cintiq 24HD */
203 TabletSetFeature(priv->common, WCM_DUALRING);
204 /* fall through */
205
206 case 0x34D: /* MobileStudio Pro 13 */
207 case 0x34E: /* MobileStudio Pro 16 */
208 case 0x398: /* MobileStudio Pro 13 */
209 case 0x399: /* MobileStudio Pro 16 */
210 case 0x3AA: /* MobileStudio Pro 16 */
211 TabletSetFeature(priv->common, WCM_LCD);
212 /* fall through */
213
214 case 0x357: /* Intuos Pro 2 M */
215 case 0x358: /* Intuos Pro 2 L */
216 case 0x360: /* Intuos Pro 2 M (Bluetooth) */
217 case 0x36a: /* Intuos Pro 2 L (Bluetooth) */
218 case 0x392: /* Intuos Pro 2 S */
219 case 0x393: /* Intuos Pro 2 S (Bluetooth) */
220 case 0x314: /* Intuos Pro S */
221 case 0x315: /* Intuos Pro M */
222 case 0x317: /* Intuos Pro L */
223 case 0x33B: /* Intuos Draw small */
224 case 0x33C: /* Intuos Art/Photo/Comic small */
225 case 0x33D: /* Intuos Draw medium */
226 case 0x33E: /* Intuos Art medium */
227 case 0x26: /* I5 */
228 case 0x27: /* I5 */
229 case 0x28: /* I5 */
230 case 0x29: /* I5 */
231 case 0x2A: /* I5 */
232 case 0xB8: /* I4 */
233 case 0xB9: /* I4 */
234 case 0xBA: /* I4 */
235 case 0xBB: /* I4 */
236 case 0xBC: /* I4 */
237 case 0xBD: /* I4 */
238 TabletSetFeature(priv->common, WCM_ROTATION);
239 /* fall through */
240
241 /* tablets with touch ring */
242 case 0x17: /* BambooFun */
243 case 0x18: /* BambooFun */
244 TabletSetFeature(priv->common, WCM_RING);
245 break;
246
247 /* tablets support dual input */
248 case 0x20: /* I1 */
249 case 0x21: /* I1 */
250 case 0x22: /* I1 */
251 case 0x23: /* I1 */
252 case 0x24: /* I1 */
253 case 0x41: /* I2 */
254 case 0x42: /* I2 */
255 case 0x43: /* I2 */
256 case 0x44: /* I2 */
257 case 0x45: /* I2 */
258 case 0x47: /* I2 */
259 TabletSetFeature(priv->common, WCM_DUALINPUT);
260 break;
261
262 /* P4 display tablets */
263 case 0x30: /* PL400 */
264 case 0x31: /* PL500 */
265 case 0x32: /* PL600 */
266 case 0x33: /* PL600SX */
267 case 0x34: /* PL550 */
268 case 0x35: /* PL800 */
269 case 0x37: /* PL700 */
270 case 0x38: /* PL510 */
271 case 0x39: /* PL710 */
272 case 0x3A: /* DTI520 */
273 case 0xC0: /* DTF720 */
274 case 0xC2: /* DTF720a */
275 case 0xC4: /* DTF521 */
276 case 0xC7: /* DTU1931 */
277 case 0xCE: /* DTU2231 */
278 case 0xF0: /* DTU1631 */
279 TabletSetFeature(priv->common, WCM_LCD);
280 break;
281
282 /* tablets support menu strips */
283 case 0x3F: /* CintiqV5 */
284 case 0xC5: /* CintiqV5 */
285 case 0xC6: /* CintiqV5 */
286 case 0xCC: /* CinitqV5 */
287 case 0xFA: /* Cintiq 22HD */
288 case 0x5B: /* Cintiq 22HDT Pen */
289 TabletSetFeature(priv->common, WCM_LCD);
290 /* fall through */
291 case 0xB0: /* I3 */
292 case 0xB1: /* I3 */
293 case 0xB2: /* I3 */
294 case 0xB3: /* I3 */
295 case 0xB4: /* I3 */
296 case 0xB5: /* I3 */
297 case 0xB7: /* I3 */
298 TabletSetFeature(priv->common, WCM_STRIP | WCM_ROTATION);
299 break;
300
301 case 0x100: /* TPC with MT */
302 case 0x101: /* TPC with MT */
303 case 0x10D: /* TPC with MT */
304 case 0x116: /* TPC with 1FGT */
305 case 0x12C: /* TPC */
306 case 0x4001: /* TPC with MT */
307 case 0x4004: /* TPC with MT (no pen on Motion) */
308 case 0x5000: /* TPC with MT */
309 case 0x5002: /* TPC with MT */
310 case 0xE2: /* TPC with 2FGT */
311 case 0xE3: /* TPC with 2FGT */
312 case 0xE5: /* TPC with MT */
313 case 0xE6: /* TPC with 2FGT */
314 case 0x93: /* TPC with 1FGT */
315 case 0x9A: /* TPC with 1FGT */
316 case 0xEC: /* TPC with 1FGT */
317 case 0xED: /* TPC with 1FGT */
318 case 0x90: /* TPC */
319 case 0x97: /* TPC */
320 case 0x9F: /* TPC */
321 case 0xEF: /* TPC */
322 TabletSetFeature(priv->common, WCM_TPC);
323 break;
324
325 case 0x304:/* Cintiq 13HD */
326 case 0x307:/* Cintiq Companion Hybrid */
327 case 0x30A:/* Cintiq Companion */
328 case 0x325:/* Cintiq Companion 2 */
329 case 0x32A:/* Cintiq 27QHD */
330 case 0x32B:/* Cintiq 27QHDT Pen */
331 case 0x333:/* Cintiq 13HDT Pen */
332 case 0x34F:/* Cintiq Pro 13 FHD */
333 case 0x350:/* Cintiq Pro 16 UHD */
334 case 0x351:/* Cintiq Pro 24 */
335 case 0x352:/* Cintiq Pro 32 */
336 case 0x37C:/* Cintiq Pro 24 Pen-Only */
337 case 0x390:/* Cintiq 16 */
338 TabletSetFeature(priv->common, WCM_ROTATION);
339 /* fall-through */
340
341 case 0xF6: /* Cintiq 24HDT Touch */
342 case 0x57: /* DTK2241 */
343 case 0x59: /* DTH2242 Pen */
344 case 0x5D: /* DTH2242 Touch */
345 case 0x5E: /* Cintiq 22HDT Touch */
346 case 0x309:/* Cintiq Companion Hybrid Touch */
347 case 0x30C:/* Cintiq Companion Touch */
348 case 0x326:/* Cintiq Companion 2 Touch */
349 case 0x32C:/* Cintiq 27QHDT Touch */
350 case 0x32F:/* DTU-1031X */
351 case 0x335:/* Cintiq 13HDT Touch */
352 case 0x336:/* DTU-1141 */
353 case 0x343:/* DTK-1651 */
354 case 0x34A:/* MobileStudio Pro 13 Touch */
355 case 0x34B:/* MobileStudio Pro 16 Touch */
356 case 0x353:/* Cintiq Pro 13 FHD Touch */
357 case 0x354:/* Cintiq Pro 13 UHD Touch */
358 case 0x355:/* Cintiq Pro 24 Touch */
359 case 0x356:/* Cintiq Pro 32 Touch */
360 case 0x359:/* DTU-1141B */
361 case 0x35A:/* DTH-1152*/
362 case 0x368:/* DTH-1152 Touch */
363 case 0x382:/* DTK-2451 */
364 case 0x37D:/* DTH-2452 */
365 case 0x37E:/* DTH-2452 Touch */
366 case 0x39A:/* MobileStudio Pro 13 Touch */
367 case 0x39B:/* MobileStudio Pro 16 Touch */
368 case 0x3AC:/* MobileStudio Pro 16 Touch */
369 TabletSetFeature(priv->common, WCM_LCD);
370 break;
371 }
372
373 #ifdef INPUT_PROP_DIRECT
374 {
375 int rc;
376 unsigned long prop[NBITS(INPUT_PROP_MAX)] = {0};
377
378 rc = ioctl(pInfo->fd, EVIOCGPROP(sizeof(prop)), prop);
379 if (rc >= 0 && ISBITSET(prop, INPUT_PROP_DIRECT))
380 TabletSetFeature(priv->common, WCM_LCD);
381 }
382 #endif
383 if (ISBITSET(common->wcmKeys, BTN_TOOL_PEN))
384 TabletSetFeature(priv->common, WCM_PEN);
385
386 if (ISBITSET (common->wcmKeys, BTN_0) ||
387 ISBITSET (common->wcmKeys, BTN_FORWARD))
388 {
389 TabletSetFeature(priv->common, WCM_PAD);
390 }
391
392 /* This handles both protocol 4 and 5 meanings of wcmKeys */
393 if (common->wcmProtocolLevel == WCM_PROTOCOL_4)
394 {
395 /* TRIPLETAP means 2 finger touch */
396 /* DOUBLETAP without TRIPLETAP means 1 finger touch */
397 if (ISBITSET(common->wcmKeys, BTN_TOOL_TRIPLETAP))
398 TabletSetFeature(priv->common, WCM_2FGT);
399 else if (ISBITSET(common->wcmKeys, BTN_TOOL_DOUBLETAP))
400 TabletSetFeature(priv->common, WCM_1FGT);
401 }
402
403 if (common->wcmProtocolLevel == WCM_PROTOCOL_GENERIC)
404 {
405 /* DOUBLETAP means 2 finger touch */
406 /* FINGER without DOUBLETAP means 1 finger touch */
407 if (ISBITSET(common->wcmKeys, BTN_TOOL_DOUBLETAP))
408 TabletSetFeature(priv->common, WCM_2FGT);
409 else if (ISBITSET(common->wcmKeys, BTN_TOOL_FINGER))
410 TabletSetFeature(priv->common, WCM_1FGT);
411 }
412
413 return ret;
414 }
415
416 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 14
417 static InputOption*
input_option_new(InputOption * list,char * key,char * value)418 input_option_new(InputOption *list, char *key, char *value)
419 {
420 InputOption *new;
421
422 new = calloc(1, sizeof(InputOption));
423 new->key = strdup(key);
424 new->value = strdup(value);
425 new->next = list;
426 return new;
427 }
428
429 static void
input_option_free_list(InputOption ** opts)430 input_option_free_list(InputOption **opts)
431 {
432 InputOption *tmp = *opts;
433 while(*opts)
434 {
435 tmp = (*opts)->next;
436 free((*opts)->key);
437 free((*opts)->value);
438 free((*opts));
439 *opts = tmp;
440 }
441 }
442 #endif
443
444 /**
445 * Duplicate xf86 options, replace the "type" option with the given type
446 * (and the name with "$name $type" and convert them to InputOption
447 *
448 * @param basename Kernel device name for this device
449 * @param type Tool type (cursor, eraser, etc.)
450 * @param serial Serial number this device should be bound to (-1 for "any")
451 */
wcmOptionDupConvert(InputInfoPtr pInfo,const char * basename,const char * type,int serial)452 static InputOption *wcmOptionDupConvert(InputInfoPtr pInfo, const char* basename, const char *type, int serial)
453 {
454 WacomDevicePtr priv = pInfo->private;
455 WacomCommonPtr common = priv->common;
456 pointer original = pInfo->options;
457 WacomToolPtr ser = common->serials;
458 InputOption *iopts = NULL;
459 char *name;
460 pointer options, o;
461 int rc;
462
463 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
464 options = xf86OptionListDuplicate(original);
465 #else
466 {
467 InputInfoRec dummy;
468
469 memset(&dummy, 0, sizeof(dummy));
470 xf86CollectInputOptions(&dummy, NULL, original);
471 options = dummy.options;
472 }
473 #endif
474 if (serial > -1)
475 {
476 while (ser->serial && ser->serial != serial)
477 ser = ser->next;
478
479 if (strlen(ser->name) > 0)
480 rc = asprintf(&name, "%s %s %s", basename, ser->name, type);
481 else
482 rc = asprintf(&name, "%s %d %s", basename, ser->serial, type);
483 }
484 else
485 rc = asprintf(&name, "%s %s", basename, type);
486
487 if (rc == -1) /* if asprintf fails, strdup will probably too... */
488 name = strdup("unknown");
489
490 options = xf86ReplaceStrOption(options, "Type", type);
491 options = xf86ReplaceStrOption(options, "Name", name);
492
493 if (serial > -1)
494 options = xf86ReplaceIntOption(options, "Serial", ser->serial);
495
496 free(name);
497
498 o = options;
499 while(o)
500 {
501 iopts = input_option_new(iopts,
502 xf86OptionName(o),
503 xf86OptionValue(o));
504 o = xf86NextOption(o);
505 }
506 xf86OptionListFree(options);
507 return iopts;
508 }
509
510
511 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
512 /**
513 * Duplicate the attributes of the given device. "product" gets the type
514 * appended, so a device of product "Wacom" will then have a product "Wacom
515 * eraser", "Wacom cursor", etc.
516 */
wcmDuplicateAttributes(InputInfoPtr pInfo,const char * type)517 static InputAttributes* wcmDuplicateAttributes(InputInfoPtr pInfo,
518 const char *type)
519 {
520 int rc;
521 InputAttributes *attr;
522 char *product;
523
524 attr = DuplicateInputAttributes(pInfo->attrs);
525 rc = asprintf(&product, "%s %s", attr->product, type);
526 free(attr->product);
527 attr->product = (rc != -1) ? product : NULL;
528 return attr;
529 }
530 #endif
531
532 /**
533 * This struct contains the necessary info for hotplugging a device later.
534 * Memory must be freed after use.
535 */
536 typedef struct {
537 InputOption *input_options;
538 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 9
539 InputAttributes *attrs;
540 #endif
541 } WacomHotplugInfo;
542
543 /**
544 * Actually hotplug the device. This function is called by the server when
545 * the WorkProcs are processed.
546 *
547 * @param client The server client. unused
548 * @param closure A pointer to a struct WcmHotplugInfo containing the
549 * necessary information to create a new device.
550 * @return TRUE to remove this function from the server's work queue.
551 */
552 static Bool
wcmHotplugDevice(ClientPtr client,pointer closure)553 wcmHotplugDevice(ClientPtr client, pointer closure )
554 {
555 WacomHotplugInfo *hotplug_info = closure;
556 DeviceIntPtr dev; /* dummy */
557
558 #if HAVE_THREADED_INPUT
559 input_lock();
560 #endif
561
562 NewInputDeviceRequest(hotplug_info->input_options,
563 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 9
564 hotplug_info->attrs,
565 #endif
566 &dev);
567 #if HAVE_THREADED_INPUT
568 input_unlock();
569 #endif
570
571 input_option_free_list(&hotplug_info->input_options);
572
573 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
574 FreeInputAttributes(hotplug_info->attrs);
575 #endif
576 free(hotplug_info);
577
578 return TRUE;
579 }
580
581 /**
582 * Queue the hotplug for one tool/device of the given type.
583 * Device has the same options as the "parent" device, type is one of
584 * erasor, stylus, pad, touch, cursor, etc.
585 * Name of the new device is set automatically to "<device name> <type>".
586 *
587 * Note that we don't actually hotplug the device here. We store the
588 * information needed to hotplug the device later and then queue the
589 * hotplug. The server will come back and call the @ref wcmHotplugDevice
590 * later.
591 *
592 * @param pInfo The parent device
593 * @param basename The base name for the device (type will be appended)
594 * @param type Type name for this tool
595 * @param serial Serial number this device should be bound to (-1 for "any")
596 */
wcmQueueHotplug(InputInfoPtr pInfo,const char * basename,const char * type,int serial)597 static void wcmQueueHotplug(InputInfoPtr pInfo, const char* basename, const char *type, int serial)
598 {
599 WacomHotplugInfo *hotplug_info;
600
601 hotplug_info = calloc(1, sizeof(WacomHotplugInfo));
602
603 if (!hotplug_info)
604 {
605 xf86Msg(X_ERROR, "%s: OOM, cannot hotplug dependent devices\n", pInfo->name);
606 return;
607 }
608
609 hotplug_info->input_options = wcmOptionDupConvert(pInfo, basename, type, serial);
610 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
611 hotplug_info->attrs = wcmDuplicateAttributes(pInfo, type);
612 #endif
613 QueueWorkProc(wcmHotplugDevice, serverClient, hotplug_info);
614 }
615
616 /**
617 * Hotplug all serial numbers configured on this device.
618 *
619 * @param basename The kernel device name
620 */
wcmHotplugSerials(InputInfoPtr pInfo,const char * basename)621 static void wcmHotplugSerials(InputInfoPtr pInfo, const char *basename)
622 {
623 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
624 WacomCommonPtr common = priv->common;
625 WacomToolPtr ser = common->serials;
626
627 while (ser)
628 {
629 xf86Msg(X_INFO, "%s: hotplugging serial %d.\n", pInfo->name, ser->serial);
630
631 if (wcmIsAValidType(pInfo, "stylus") &&
632 (ser->typeid & STYLUS_ID))
633 wcmQueueHotplug(pInfo, basename, "stylus", ser->serial);
634
635 if (wcmIsAValidType(pInfo, "eraser") &&
636 (ser->typeid & ERASER_ID))
637 wcmQueueHotplug(pInfo, basename, "eraser", ser->serial);
638
639 if (wcmIsAValidType(pInfo, "cursor") &&
640 (ser->typeid & CURSOR_ID))
641 wcmQueueHotplug(pInfo, basename, "cursor", ser->serial);
642
643 ser = ser->next;
644 }
645 }
646
wcmHotplugOthers(InputInfoPtr pInfo,const char * basename)647 void wcmHotplugOthers(InputInfoPtr pInfo, const char *basename)
648 {
649 int i, skip = 1;
650
651 xf86Msg(X_INFO, "%s: hotplugging dependent devices.\n", pInfo->name);
652
653 /* same loop is used to init the first device, if we get here we
654 * need to start at the second one */
655 for (i = 0; i < ARRAY_SIZE(wcmType); i++)
656 {
657 if (wcmIsAValidType(pInfo, wcmType[i].type))
658 {
659 if (skip)
660 skip = 0;
661 else
662 wcmQueueHotplug(pInfo, basename, wcmType[i].type, -1);
663 }
664 }
665
666 wcmHotplugSerials(pInfo, basename);
667
668 xf86Msg(X_INFO, "%s: hotplugging completed.\n", pInfo->name);
669 }
670
671 /**
672 * Return 1 if the device needs auto-hotplugging from within the driver.
673 * This is the case if we don't get passed a "type" option (invalid in
674 * xorg.conf configurations) and we come from HAL, udev or whatever future
675 * config backend.
676 *
677 * This changes the source to _driver/wacom, all auto-hotplugged devices
678 * will have the same source.
679 */
wcmNeedAutoHotplug(InputInfoPtr pInfo,char ** type)680 int wcmNeedAutoHotplug(InputInfoPtr pInfo, char **type)
681 {
682 char *source = xf86CheckStrOption(pInfo->options, "_source", NULL);
683 int i;
684 int rc = 0;
685
686 if (*type) /* type specified, don't hotplug */
687 goto out;
688
689 if (!source) /* xorg.conf device, don't auto-pick type */
690 goto out;
691 if (strcmp(source, "server/hal") &&
692 strcmp(source, "server/udev") &&
693 strcmp(source, "server/devd") &&
694 strcmp(source, "server/wscons"))
695 goto out;
696
697 /* no type specified, so we need to pick the first one applicable
698 * for our device */
699 for (i = 0; i < ARRAY_SIZE(wcmType); i++)
700 {
701 if (wcmIsAValidType(pInfo, wcmType[i].type))
702 {
703 free(*type);
704 *type = strdup(wcmType[i].type);
705 break;
706 }
707 }
708
709 if (!*type)
710 goto out;
711
712 xf86Msg(X_INFO, "%s: type not specified, assuming '%s'.\n", pInfo->name, *type);
713 xf86Msg(X_INFO, "%s: other types will be automatically added.\n", pInfo->name);
714
715 /* Note: wcmIsHotpluggedDevice() relies on this */
716 pInfo->options = xf86AddNewOption(pInfo->options, "Type", *type);
717 pInfo->options = xf86ReplaceStrOption(pInfo->options, "_source", "_driver/wacom");
718
719 rc = 1;
720
721 free(source);
722 out:
723 return rc;
724 }
725
wcmParseSerials(InputInfoPtr pInfo)726 int wcmParseSerials (InputInfoPtr pInfo)
727 {
728 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
729 WacomCommonPtr common = priv->common;
730 char *s;
731
732 if (common->serials)
733 {
734 return 0; /*Parse has been already done*/
735 }
736
737 s = xf86SetStrOption(pInfo->options, "ToolSerials", NULL);
738 if (s) /*Dont parse again, if the commons have values already*/
739 {
740 char* tok = strtok(s, ";");
741 while (tok != NULL)
742 {
743 int serial, nmatch;
744 char type[strlen(tok) + 1];
745 char name[strlen(tok) + 1];
746 WacomToolPtr ser = calloc(1, sizeof(WacomTool));
747
748 if (ser == NULL)
749 return 1;
750
751 nmatch = sscanf(tok,"%d,%[a-z],%[A-Za-z ]",&serial, type, name);
752
753 if (nmatch < 1)
754 {
755 xf86Msg(X_ERROR, "%s: %s is invalid serial string.\n",
756 pInfo->name, tok);
757 free(ser);
758 return 1;
759 }
760
761 if (nmatch >= 1)
762 {
763 xf86Msg(X_CONFIG, "%s: Tool serial %d found.\n",
764 pInfo->name, serial);
765
766 ser->serial = serial;
767
768 ser->typeid = STYLUS_ID | ERASER_ID; /*Default to both tools*/
769 }
770
771 if (nmatch >= 2)
772 {
773 xf86Msg(X_CONFIG, "%s: Tool %d has type %s.\n",
774 pInfo->name, serial, type);
775 if ((strcmp(type, "pen") == 0) || (strcmp(type, "airbrush") == 0))
776 ser->typeid = STYLUS_ID | ERASER_ID;
777 else if (strcmp(type, "artpen") == 0)
778 ser->typeid = STYLUS_ID;
779 else if (strcmp(type, "cursor") == 0)
780 ser->typeid = CURSOR_ID;
781 else xf86Msg(X_CONFIG, "%s: Invalid type %s, defaulting to pen.\n",
782 pInfo->name, type);
783 }
784
785 if (nmatch == 3)
786 {
787 xf86Msg(X_CONFIG, "%s: Tool %d is named %s.\n",
788 pInfo->name, serial, name);
789 ser->name = strdup(name);
790 }
791 else ser->name = strdup(""); /*no name yet*/
792
793 if (common->serials == NULL)
794 common->serials = ser;
795 else
796 {
797 WacomToolPtr tool = common->serials;
798 while (tool->next)
799 tool = tool->next;
800 tool->next = ser;
801 }
802
803 tok = strtok(NULL,";");
804 }
805 }
806 return 0;
807 }
808
809 /**
810 * Parse the pre-init options for this device. Most useful for options
811 * needed to properly init a device (baud rate for example).
812 *
813 * Note that parameters is_primary and is_dependent are mutually exclusive,
814 * though both may be false in the case of an xorg.conf device.
815 *
816 * @param is_primary True if the device is the parent device for
817 * hotplugging, False if the device is a depent or xorg.conf device.
818 * @param is_hotplugged True if the device is a dependent device, FALSE
819 * otherwise.
820 * @retval True on success or False otherwise.
821 */
wcmPreInitParseOptions(InputInfoPtr pInfo,Bool is_primary,Bool is_dependent)822 Bool wcmPreInitParseOptions(InputInfoPtr pInfo, Bool is_primary,
823 Bool is_dependent)
824 {
825 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
826 WacomCommonPtr common = priv->common;
827 char *s;
828 int i;
829 WacomToolPtr tool = NULL;
830 int tpc_button_is_on;
831
832 /* Optional configuration */
833 s = xf86SetStrOption(pInfo->options, "Mode", NULL);
834
835 if (s && (xf86NameCmp(s, "absolute") == 0))
836 set_absolute(pInfo, TRUE);
837 else if (s && (xf86NameCmp(s, "relative") == 0))
838 set_absolute(pInfo, FALSE);
839 else
840 {
841 if (s)
842 xf86Msg(X_ERROR, "%s: invalid Mode (should be absolute"
843 " or relative). Using default.\n", pInfo->name);
844
845 /* If Mode not specified or is invalid then rely on
846 * Type specific defaults from initialization.
847 */
848 }
849
850 free(s);
851
852 /* Pad is always in absolute mode.
853 * The pad also defaults to wheel scrolling, unlike the pens
854 * (interesting effects happen on ArtPen and others with build-in
855 * wheels)
856 */
857 if (IsPad(priv))
858 {
859 priv->wheel_default[WHEEL_ABS_UP] = priv->wheel_default[WHEEL2_ABS_UP] = 4;
860 priv->wheel_default[WHEEL_ABS_DN] = priv->wheel_default[WHEEL2_ABS_DN] = 5;
861 set_absolute(pInfo, TRUE);
862 }
863
864 s = xf86SetStrOption(pInfo->options, "Rotate", NULL);
865
866 if (s)
867 {
868 int rotation = ROTATE_NONE;
869
870 if (xf86NameCmp(s, "CW") == 0)
871 rotation = ROTATE_CW;
872 else if (xf86NameCmp(s, "CCW") ==0)
873 rotation = ROTATE_CCW;
874 else if (xf86NameCmp(s, "HALF") ==0)
875 rotation = ROTATE_HALF;
876 else if (xf86NameCmp(s, "NONE") !=0)
877 {
878 xf86Msg(X_ERROR, "%s: invalid Rotate option '%s'.\n",
879 pInfo->name, s);
880 goto error;
881 }
882
883 if (is_dependent && rotation != common->wcmRotate)
884 xf86Msg(X_INFO, "%s: ignoring rotation of dependent"
885 " device\n", pInfo->name);
886 else
887 wcmRotateTablet(pInfo, rotation);
888 free(s);
889 }
890
891 common->wcmRawSample = xf86SetIntOption(pInfo->options, "RawSample",
892 common->wcmRawSample);
893 if (common->wcmRawSample < 1 || common->wcmRawSample > MAX_SAMPLES)
894 {
895 xf86Msg(X_ERROR, "%s: RawSample setting '%d' out of range [1..%d]. Using default.\n",
896 pInfo->name, common->wcmRawSample, MAX_SAMPLES);
897 common->wcmRawSample = DEFAULT_SAMPLES;
898 }
899
900 common->wcmSuppress = xf86SetIntOption(pInfo->options, "Suppress",
901 common->wcmSuppress);
902 if (common->wcmSuppress != 0) /* 0 disables suppression */
903 {
904 if (common->wcmSuppress > MAX_SUPPRESS)
905 common->wcmSuppress = MAX_SUPPRESS;
906 if (common->wcmSuppress < DEFAULT_SUPPRESS)
907 common->wcmSuppress = DEFAULT_SUPPRESS;
908 }
909
910 /* pressure curve takes control points x1,y1,x2,y2
911 * values in range from 0..100.
912 * Linear curve is 0,0,100,100
913 * Slightly depressed curve might be 5,0,100,95
914 * Slightly raised curve might be 0,5,95,100
915 */
916 s = xf86SetStrOption(pInfo->options, "PressCurve", "0,0,100,100");
917 if (s && (IsPen(priv) || IsTouch(priv)))
918 {
919 int a,b,c,d;
920 if ((sscanf(s,"%d,%d,%d,%d",&a,&b,&c,&d) != 4) ||
921 !wcmCheckPressureCurveValues(a, b, c, d))
922 xf86Msg(X_CONFIG, "%s: PressCurve not valid\n",
923 pInfo->name);
924 else
925 wcmSetPressureCurve(priv,a,b,c,d);
926 }
927 free(s);
928
929 if (xf86SetBoolOption(pInfo->options, "Pressure2K", 0)) {
930 xf86Msg(X_CONFIG, "%s: Using 2K pressure levels\n", pInfo->name);
931 priv->maxCurve = 2048;
932 }
933
934 /*Serials of tools we want hotpluged*/
935 if (wcmParseSerials (pInfo) != 0)
936 goto error;
937
938 if (IsTablet(priv))
939 {
940 const char *prop = IsCursor(priv) ? "CursorProx" : "StylusProx";
941 priv->wcmProxoutDist = xf86SetIntOption(pInfo->options, prop, 0);
942 if (priv->wcmProxoutDist < 0 ||
943 priv->wcmProxoutDist > common->wcmMaxDist)
944 xf86Msg(X_CONFIG, "%s: %s invalid %d \n",
945 pInfo->name, prop, priv->wcmProxoutDist);
946 priv->wcmSurfaceDist = -1;
947 }
948
949 priv->topX = xf86SetIntOption(pInfo->options, "TopX", 0);
950 priv->topY = xf86SetIntOption(pInfo->options, "TopY", 0);
951 priv->bottomX = xf86SetIntOption(pInfo->options, "BottomX", 0);
952 priv->bottomY = xf86SetIntOption(pInfo->options, "BottomY", 0);
953 priv->serial = xf86SetIntOption(pInfo->options, "Serial", 0);
954
955 tool = priv->tool;
956 tool->serial = priv->serial;
957
958 common->wcmPanscrollThreshold = xf86SetIntOption(pInfo->options, "PanScrollThreshold",
959 common->wcmPanscrollThreshold);
960
961 /* The first device doesn't need to add any tools/areas as it
962 * will be the first anyway. So if different, add tool
963 * and/or area to the existing lists
964 */
965 if(tool != common->wcmTool)
966 {
967 WacomToolPtr toollist = NULL;
968 for(toollist = common->wcmTool; toollist; toollist = toollist->next)
969 if(tool->typeid == toollist->typeid && tool->serial == toollist->serial)
970 break;
971
972 if(toollist) /* Already have a tool with the same type/serial */
973 {
974 xf86Msg(X_ERROR, "%s: already have a tool with type/serial %d/%d.\n",
975 pInfo->name, tool->typeid, tool->serial);
976 goto error;
977 } else /* No match on existing tool/serial, add tool to the end of the list */
978 {
979 toollist = common->wcmTool;
980 while(toollist->next)
981 toollist = toollist->next;
982 toollist->next = tool;
983 }
984 }
985
986 common->wcmThreshold = xf86SetIntOption(pInfo->options, "Threshold",
987 common->wcmThreshold);
988
989 if (xf86SetBoolOption(pInfo->options, "ButtonsOnly", 0))
990 priv->flags |= BUTTONS_ONLY_FLAG;
991
992 /* TPCButton on for Tablet PC by default */
993 tpc_button_is_on = xf86SetBoolOption(pInfo->options, "TPCButton",
994 TabletHasFeature(common, WCM_TPC));
995
996 if (is_primary || IsStylus(priv))
997 common->wcmTPCButton = tpc_button_is_on;
998 else if (tpc_button_is_on != common->wcmTPCButton)
999 xf86Msg(X_WARNING, "%s: TPCButton option can only be set "
1000 "by stylus.\n", pInfo->name);
1001
1002 /* a single or double touch device */
1003 if (TabletHasFeature(common, WCM_1FGT) ||
1004 TabletHasFeature(common, WCM_2FGT))
1005 {
1006 int touch_is_on;
1007
1008 /* TouchDefault was off for all devices
1009 * except when touch is supported */
1010 common->wcmTouchDefault = 1;
1011
1012 touch_is_on = xf86SetBoolOption(pInfo->options, "Touch",
1013 common->wcmTouchDefault);
1014
1015 if (is_primary || IsTouch(priv))
1016 common->wcmTouch = touch_is_on;
1017 else if (touch_is_on != common->wcmTouch)
1018 xf86Msg(X_WARNING, "%s: Touch option can only be set "
1019 "by a touch tool.\n", pInfo->name);
1020
1021 if (TabletHasFeature(common, WCM_1FGT))
1022 common->wcmMaxContacts = 1;
1023 else
1024 common->wcmMaxContacts = 2;
1025 }
1026
1027 /* 2FG touch device */
1028 if (TabletHasFeature(common, WCM_2FGT))
1029 {
1030 int gesture_is_on;
1031 Bool gesture_default = TabletHasFeature(priv->common, WCM_LCD) ? FALSE : TRUE;
1032
1033 gesture_is_on = xf86SetBoolOption(pInfo->options, "Gesture",
1034 gesture_default);
1035
1036 if (is_primary || IsTouch(priv))
1037 common->wcmGesture = gesture_is_on;
1038 else if (gesture_is_on != common->wcmGesture)
1039 xf86Msg(X_WARNING, "%s: Touch gesture option can only "
1040 "be set by a touch tool.\n", pInfo->name);
1041
1042 common->wcmGestureParameters.wcmTapTime =
1043 xf86SetIntOption(pInfo->options, "TapTime",
1044 common->wcmGestureParameters.wcmTapTime);
1045 }
1046
1047 if (IsStylus(priv) || IsEraser(priv)) {
1048 common->wcmPressureRecalibration
1049 = xf86SetBoolOption(pInfo->options,
1050 "PressureRecalibration", 1);
1051 }
1052
1053 /* Swap stylus buttons 2 and 3 for Tablet PCs */
1054 if (TabletHasFeature(common, WCM_TPC) && IsStylus(priv))
1055 {
1056 priv->button_default[1] = 3;
1057 priv->button_default[2] = 2;
1058 }
1059
1060 for (i=0; i<WCM_MAX_BUTTONS; i++)
1061 {
1062 char b[12];
1063 sprintf(b, "Button%d", i+1);
1064 priv->button_default[i] = xf86SetIntOption(pInfo->options, b, priv->button_default[i]);
1065 }
1066
1067 /* Now parse class-specific options */
1068 if (common->wcmDevCls->ParseOptions &&
1069 !common->wcmDevCls->ParseOptions(pInfo))
1070 goto error;
1071
1072 return TRUE;
1073 error:
1074 return FALSE;
1075 }
1076
1077 /* The values were based on trial and error with a 3rd-gen Bamboo */
1078 #define WCM_DEFAULT_MM_XRES (27.8 * 1000)
1079 #define WCM_DEFAULT_MM_YRES (44.5 * 1000)
1080 #define WCM_ZOOM_DISTANCE_MM 6.5
1081 #define WCM_SCROLL_DISTANCE_MM 1.8
1082
1083 /**
1084 * Parse post-init options for this device. Useful for overriding HW
1085 * specific options computed during init phase (HW distances for example).
1086 *
1087 * Note that parameters is_primary and is_dependent are mutually exclusive,
1088 * though both may be false in the case of an xorg.conf device.
1089 *
1090 * @param is_primary True if the device is the parent device for
1091 * hotplugging, False if the device is a depent or xorg.conf device.
1092 * @param is_hotplugged True if the device is a dependent device, FALSE
1093 * otherwise.
1094 * @retval True on success or False otherwise.
1095 */
wcmPostInitParseOptions(InputInfoPtr pInfo,Bool is_primary,Bool is_dependent)1096 Bool wcmPostInitParseOptions(InputInfoPtr pInfo, Bool is_primary,
1097 Bool is_dependent)
1098 {
1099 WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
1100 WacomCommonPtr common = priv->common;
1101
1102 common->wcmMaxZ = xf86SetIntOption(pInfo->options, "MaxZ",
1103 common->wcmMaxZ);
1104
1105 /* 2FG touch device */
1106 if (TabletHasFeature(common, WCM_2FGT) && IsTouch(priv))
1107 {
1108 int x_res = common->wcmTouchResolX ? common->wcmTouchResolX : WCM_DEFAULT_MM_XRES;
1109 int y_res = common->wcmTouchResolY ? common->wcmTouchResolY : WCM_DEFAULT_MM_YRES;
1110 int zoom_distance = WCM_ZOOM_DISTANCE_MM * x_res / 1000;
1111 int scroll_distance = WCM_SCROLL_DISTANCE_MM * y_res / 1000;
1112
1113 common->wcmGestureParameters.wcmZoomDistance =
1114 xf86SetIntOption(pInfo->options, "ZoomDistance",
1115 zoom_distance);
1116
1117 common->wcmGestureParameters.wcmScrollDistance =
1118 xf86SetIntOption(pInfo->options, "ScrollDistance",
1119 scroll_distance);
1120 }
1121
1122
1123 return TRUE;
1124 }
1125
1126 /* vim: set noexpandtab tabstop=8 shiftwidth=8: */
1127