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