1 /*
2  * Copyright 1995-2002 by Frederic Lepied, France. <Lepied@XFree86.org>
3  * Copyright 2002-2010 by Ping Cheng, Wacom. <pingc@wacom.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 /*
21  * This driver is currently able to handle USB Wacom IV and V, serial ISDV4,
22  * and bluetooth protocols.
23  *
24  * Wacom V protocol work done by Raph Levien <raph@gtk.org> and
25  * Frédéric Lepied <lepied@xfree86.org>.
26  *
27  * Modified for Linux USB by MATSUMURA Namihiko,
28  * Daniel Egger, Germany. <egger@suse.de>,
29  * Frederic Lepied <lepied@xfree86.org>,
30  * Brion Vibber <brion@pobox.com>,
31  * Aaron Optimizer Digulla <digulla@hepe.com>,
32  * Jonathan Layes <jonathan@layes.com>,
33  * John Joganic <jej@j-arkadia.com>,
34  * Magnus Vigerlöf <Magnus.Vigerlof@ipbo.se>,
35  * Peter Hutterer <peter.hutterer@redhat.com>.
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41 
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 
46 #include "xf86Wacom.h"
47 #include <xf86_OSproc.h>
48 #include <exevents.h>           /* Needed for InitValuator/Proximity stuff */
49 
50 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
51 #include <xserver-properties.h>
52 #include <X11/extensions/XKB.h>
53 #include <xkbsrv.h>
54 #else
55 #define XIGetKnownProperty(prop) 0
56 #endif
57 
58 #ifndef XI86_SERVER_FD
59 #define XI86_SERVER_FD 0x20
60 #endif
61 
62 static int wcmDevOpen(DeviceIntPtr pWcm);
63 static int wcmReady(InputInfoPtr pInfo);
64 static void wcmDevReadInput(InputInfoPtr pInfo);
65 static void wcmDevControlProc(DeviceIntPtr device, PtrCtrl* ctrl);
66 int wcmDevChangeControl(InputInfoPtr pInfo, xDeviceCtl * control);
67 static void wcmDevClose(InputInfoPtr pInfo);
68 static int wcmDevProc(DeviceIntPtr pWcm, int what);
69 
70 WacomModule gWacomModule =
71 {
72 	NULL,           /* input driver pointer */
73 
74 	/* device procedures */
75 	wcmDevOpen,
76 	wcmDevReadInput,
77 	wcmDevControlProc,
78 	wcmDevChangeControl,
79 	wcmDevClose,
80 	wcmDevProc,
81 	wcmDevSwitchMode,
82 };
83 
wcmKbdLedCallback(DeviceIntPtr di,LedCtrl * lcp)84 static void wcmKbdLedCallback(DeviceIntPtr di, LedCtrl * lcp)
85 {
86 }
87 
wcmKbdCtrlCallback(DeviceIntPtr di,KeybdCtrl * ctrl)88 static void wcmKbdCtrlCallback(DeviceIntPtr di, KeybdCtrl* ctrl)
89 {
90 }
91 
92 /*****************************************************************************
93  * wcmInitialToolSize --
94  *    Initialize logical size and resolution for individual tool.
95  ****************************************************************************/
96 
97 TEST_NON_STATIC void
wcmInitialToolSize(InputInfoPtr pInfo)98 wcmInitialToolSize(InputInfoPtr pInfo)
99 {
100 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
101 	WacomCommonPtr common = priv->common;
102 
103 	/* assign max and resolution here since we don't get them during
104 	 * the configuration stage */
105 	if (IsTouch(priv))
106 	{
107 		priv->maxX = common->wcmMaxTouchX;
108 		priv->maxY = common->wcmMaxTouchY;
109 		priv->resolX = common->wcmTouchResolX;
110 		priv->resolY = common->wcmTouchResolY;
111 	}
112 	else
113 	{
114 		priv->minX = common->wcmMinX;
115 		priv->minY = common->wcmMinY;
116 		priv->maxX = common->wcmMaxX;
117 		priv->maxY = common->wcmMaxY;
118 		priv->resolX = common->wcmResolX;
119 		priv->resolY = common->wcmResolY;
120 	}
121 
122 	if (!priv->topX)
123 		priv->topX = priv->minX;
124 	if (!priv->topY)
125 		priv->topY = priv->minY;
126 	if (!priv->bottomX)
127 		priv->bottomX = priv->maxX;
128 	if (!priv->bottomY)
129 		priv->bottomY = priv->maxY;
130 
131 	return;
132 }
133 
wcmInitAxis(DeviceIntPtr dev,int axis,Atom label,int min,int max,int res,int min_res,int max_res,int mode)134 static void wcmInitAxis(DeviceIntPtr dev, int axis, Atom label, int min, int max, int res, int min_res, int max_res, int mode) {
135 	InitValuatorAxisStruct(dev, axis,
136 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
137 	                       label,
138 #endif
139 	                       min, max, res, min_res, max_res
140 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 12
141 	                       ,mode
142 #endif
143 	);
144 }
145 
146 /**
147  * Initialize the device axes with their proper attributes.
148  *
149  * For each axis on the device, we need to provide X with its attributes
150  * so that its values can be interpreted properly. To support older X
151  * servers without axis labels, each axis index has a de-facto meaning.
152  * Any de-facto defined axis index left unused is initialized with default
153  * attributes.
154  */
wcmInitAxes(DeviceIntPtr pWcm)155 static int wcmInitAxes(DeviceIntPtr pWcm)
156 {
157 	InputInfoPtr pInfo = (InputInfoPtr)pWcm->public.devicePrivate;
158 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
159 	WacomCommonPtr common = priv->common;
160 
161 	Atom label;
162 	int index;
163 	int min, max, min_res, max_res, res;
164 	int mode;
165 
166 	/* first valuator: x */
167 	index = 0;
168 	label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_X);
169 	min = priv->topX;
170 	max = priv->bottomX;
171 	min_res = 0;
172 	max_res = priv->resolX;
173 	res = priv->resolX;
174 	mode = Absolute;
175 
176 	wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
177 
178 
179 	/* second valuator: y */
180 	index = 1;
181 	label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_Y);
182 	min = priv->topY;
183 	max = priv->bottomY;
184 	min_res = 0;
185 	max_res = priv->resolY;
186 	res = priv->resolY;
187 	mode = Absolute;
188 
189 	wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
190 
191 
192 	/* third valuator: pressure */
193 	index = 2;
194 	label = None;
195 	mode = Absolute;
196 	min_res = max_res = res = 1;
197 	min = 0;
198 	max = 1;
199 
200 	if (!IsPad(priv))
201 	{
202 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_PRESSURE);
203 		max = priv->maxCurve;
204 	}
205 
206 	wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
207 
208 
209 	/* fourth valuator: tilt-x, cursor:z-rotation, pad:strip-x */
210 	index = 3;
211 	label = None;
212 	mode = Absolute;
213 	min_res = max_res = res = 1;
214 	min = 0;
215 	max = 1;
216 
217 	if (IsPen(priv))
218 	{
219 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_X),
220 		min_res = max_res = res = round(TILT_RES);
221 		min = TILT_MIN;
222 		max = TILT_MAX;
223 	}
224 	else if (IsCursor(priv))
225 	{
226 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_RZ);
227 		min = MIN_ROTATION;
228 		max = MIN_ROTATION + MAX_ROTATION_RANGE - 1;
229 	}
230 	else if (IsPad(priv) && TabletHasFeature(common, WCM_STRIP))
231 	{ /* XXX: what is this axis label? */
232 		max = common->wcmMaxStripX;
233 	}
234 
235 	wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
236 
237 
238 	/* fifth valuator: tilt-y, cursor:throttle, pad:strip-y */
239 	index = 4;
240 	label = None;
241 	mode = Absolute;
242 	min_res = max_res = res = 1;
243 	min = 0;
244 	max = 1;
245 
246 	if (IsPen(priv))
247 	{
248 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_TILT_Y);
249 		min_res = max_res = res = round(TILT_RES);
250 		min = TILT_MIN;
251 		max = TILT_MAX;
252 	}
253 	else if (IsCursor(priv))
254 	{
255 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_THROTTLE);
256 		min = -1023;
257 		max = 1023;
258 	}
259 	else if (IsPad(priv) && TabletHasFeature(common, WCM_STRIP))
260 	{ /* XXX: what is this axis label? */
261 		max = common->wcmMaxStripY;
262 	}
263 
264 	wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
265 
266 
267 	/* sixth valuator: airbrush: abs-wheel, artpen: rotation, pad:abs-wheel */
268 	index = 5;
269 	label = None;
270 	mode = Absolute;
271 	min_res = max_res = res = 1;
272 	min = 0;
273 	max = 1;
274 
275 	if (IsStylus(priv))
276 	{
277 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_WHEEL);
278 		max = MAX_ROTATION_RANGE + MIN_ROTATION - 1;
279 		min = MIN_ROTATION;
280 	}
281 	else if ((TabletHasFeature(common, WCM_RING)) && IsPad(priv))
282 	{
283 		/* Touch ring */
284 		label = XIGetKnownProperty(AXIS_LABEL_PROP_ABS_WHEEL);
285 		min = common->wcmMinRing;
286 		max = common->wcmMaxRing;
287 	}
288 
289 	wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
290 
291 
292 	/* seventh valuator: abswheel2 */
293 	if ((TabletHasFeature(common, WCM_DUALRING)) && IsPad(priv))
294 	{
295 		/* XXX: what is this axis label? */
296 		index = 6;
297 		label = None;
298 		mode = Absolute;
299 		min_res = max_res = res = 1;
300 
301 		min = common->wcmMinRing;
302 		max = common->wcmMaxRing;
303 
304 		wcmInitAxis(pInfo->dev, index, label, min, max, res, min_res, max_res, mode);
305 	}
306 
307 	return TRUE;
308 }
309 
310 /*****************************************************************************
311  * wcmDevInit --
312  *    Set up the device's buttons, axes and keys
313  ****************************************************************************/
314 
wcmDevInit(DeviceIntPtr pWcm)315 static int wcmDevInit(DeviceIntPtr pWcm)
316 {
317 	InputInfoPtr pInfo = (InputInfoPtr)pWcm->public.devicePrivate;
318 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
319 	WacomCommonPtr common =	priv->common;
320 	unsigned char butmap[WCM_MAX_BUTTONS+1];
321 	int nbaxes, nbbuttons, nbkeys;
322 	int loop;
323 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
324         Atom btn_labels[WCM_MAX_BUTTONS] = {0};
325         Atom axis_labels[MAX_VALUATORS] = {0};
326 #endif
327 
328 	/* Detect tablet configuration, if possible */
329 	if (priv->common->wcmModel->DetectConfig)
330 		priv->common->wcmModel->DetectConfig (pInfo);
331 
332 	nbaxes = priv->naxes;       /* X, Y, Pressure, Tilt-X, Tilt-Y, Wheel */
333 	nbbuttons = priv->nbuttons; /* Use actual number of buttons, if possible */
334 
335 	if (IsPad(priv) && TabletHasFeature(priv->common, WCM_DUALRING))
336 		nbaxes = priv->naxes = nbaxes + 1; /* ABS wheel 2 */
337 
338 	/* if more than 3 buttons, offset by the four scroll buttons,
339 	 * otherwise, alloc 7 buttons for scroll wheel. */
340 	nbbuttons = min(max(nbbuttons + 4, 7), WCM_MAX_BUTTONS);
341 	nbkeys = nbbuttons;         /* Same number of keys since any button may be
342 	                             * configured as an either mouse button or key */
343 
344 	DBG(10, priv,
345 		"(%s) %d buttons, %d keys, %d axes\n",
346 		pInfo->type_name,
347 		nbbuttons, nbkeys, nbaxes);
348 
349 	for(loop=1; loop<=nbbuttons; loop++)
350 		butmap[loop] = loop;
351 
352 	/* FIXME: button labels would be nice */
353 	if (InitButtonClassDeviceStruct(pInfo->dev, nbbuttons,
354 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
355 					btn_labels,
356 #endif
357 					butmap) == FALSE)
358 	{
359 		xf86Msg(X_ERROR, "%s: unable to allocate Button class device\n", pInfo->name);
360 		return FALSE;
361 	}
362 
363 	if (InitFocusClassDeviceStruct(pInfo->dev) == FALSE)
364 	{
365 		xf86Msg(X_ERROR, "%s: unable to init Focus class device\n", pInfo->name);
366 		return FALSE;
367 	}
368 
369 	if (InitPtrFeedbackClassDeviceStruct(pInfo->dev,
370 		wcmDevControlProc) == FALSE)
371 	{
372 		xf86Msg(X_ERROR, "%s: unable to init ptr feedback\n", pInfo->name);
373 		return FALSE;
374 	}
375 
376 	if (InitProximityClassDeviceStruct(pInfo->dev) == FALSE)
377 	{
378 			xf86Msg(X_ERROR, "%s: unable to init proximity class device\n", pInfo->name);
379 			return FALSE;
380 	}
381 
382 	if (!nbaxes || nbaxes > 7)
383 		nbaxes = priv->naxes = 7;
384 
385 	/* axis_labels is just zeros, we set up each valuator with the
386 	 * correct property later */
387 	if (InitValuatorClassDeviceStruct(pInfo->dev, nbaxes,
388 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
389 					  axis_labels,
390 #endif
391 					  GetMotionHistorySize(),
392 					  (is_absolute(pInfo) ?  Absolute : Relative) | OutOfProximity) == FALSE)
393 	{
394 		xf86Msg(X_ERROR, "%s: unable to allocate Valuator class device\n", pInfo->name);
395 		return FALSE;
396 	}
397 
398 
399 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
400 	if (!InitKeyboardDeviceStruct(pInfo->dev, NULL, NULL, wcmKbdCtrlCallback)) {
401 		xf86Msg(X_ERROR, "%s: unable to init kbd device struct\n", pInfo->name);
402 		return FALSE;
403 	}
404 #endif
405 	if(InitLedFeedbackClassDeviceStruct (pInfo->dev, wcmKbdLedCallback) == FALSE) {
406 		xf86Msg(X_ERROR, "%s: unable to init led feedback device struct\n", pInfo->name);
407 		return FALSE;
408 	}
409 
410 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 16
411 	if (IsTouch(priv)) {
412 		if (!InitTouchClassDeviceStruct(pInfo->dev, common->wcmMaxContacts,
413 						TabletHasFeature(common, WCM_LCD) ? XIDirectTouch : XIDependentTouch,
414 						2))
415 		{
416 			xf86Msg(X_ERROR, "Unable to init touch class device struct!\n");
417 			return FALSE;
418 		}
419 		priv->common->touch_mask = valuator_mask_new(2);
420 	}
421 #endif
422 
423 	if (!IsPad(priv))
424 	{
425 		wcmInitialToolSize(pInfo);
426 	}
427 
428 	if (!wcmInitAxes(pWcm))
429 		return FALSE;
430 
431 	InitWcmDeviceProperties(pInfo);
432 	XIRegisterPropertyHandler(pInfo->dev, wcmSetProperty, wcmGetProperty, wcmDeleteProperty);
433 
434 	return TRUE;
435 }
436 
wcmIsWacomDevice(char * fname)437 Bool wcmIsWacomDevice (char* fname)
438 {
439 	int fd = -1;
440 	struct input_id id;
441 
442 	SYSCALL(fd = open(fname, O_RDONLY));
443 	if (fd < 0)
444 		return FALSE;
445 
446 	if (ioctl(fd, EVIOCGID, &id) < 0)
447 	{
448 		SYSCALL(close(fd));
449 		return FALSE;
450 	}
451 
452 	SYSCALL(close(fd));
453 
454 	switch(id.vendor)
455 	{
456 		case WACOM_VENDOR_ID:
457 		case WALTOP_VENDOR_ID:
458 		case HANWANG_VENDOR_ID:
459 		case LENOVO_VENDOR_ID:
460 			return TRUE;
461 		default:
462 			break;
463 	}
464 	return FALSE;
465 }
466 
467 /*****************************************************************************
468  * wcmEventAutoDevProbe -- Probe for right input device
469  ****************************************************************************/
470 #define DEV_INPUT_EVENT "/dev/input/event%d"
471 #define EVDEV_MINORS    32
wcmEventAutoDevProbe(InputInfoPtr pInfo)472 char *wcmEventAutoDevProbe (InputInfoPtr pInfo)
473 {
474 	/* We are trying to find the right eventX device */
475 	int i = 0, wait = 0;
476 	const int max_wait = 2000;
477 
478 	/* If device is not available after Resume, wait some ms */
479 	while (wait <= max_wait)
480 	{
481 		for (i = 0; i < EVDEV_MINORS; i++)
482 		{
483 			char fname[64];
484 			Bool is_wacom;
485 
486 			sprintf(fname, DEV_INPUT_EVENT, i);
487 			is_wacom = wcmIsWacomDevice(fname);
488 			if (is_wacom)
489 			{
490 				xf86Msg(X_PROBED, "%s: probed device is %s (waited %d msec)\n",
491 					pInfo->name, fname, wait);
492 				xf86ReplaceStrOption(pInfo->options, "Device", fname);
493 
494 				/* this assumes there is only one Wacom device on the system */
495 				return xf86CheckStrOption(pInfo->options, "Device", NULL);
496 			}
497 		}
498 		wait += 100;
499 		xf86Msg(X_ERROR, "%s: waiting 100 msec (total %dms) for device to become ready\n", pInfo->name, wait);
500 		usleep(100*1000);
501 	}
502 	xf86Msg(X_ERROR, "%s: no Wacom event device found (checked %d nodes, waited %d msec)\n",
503 		pInfo->name, i + 1, wait);
504 	xf86Msg(X_ERROR, "%s: unable to probe device\n", pInfo->name);
505 	return NULL;
506 }
507 
508 /*****************************************************************************
509  * wcmOpen --
510  ****************************************************************************/
511 
wcmOpen(InputInfoPtr pInfo)512 Bool wcmOpen(InputInfoPtr pInfo)
513 {
514 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
515 	WacomCommonPtr common = priv->common;
516 
517 	DBG(1, priv, "opening device file\n");
518 
519 	pInfo->fd = xf86OpenSerial(pInfo->options);
520 	if (pInfo->fd < 0)
521 	{
522 		xf86Msg(X_ERROR, "%s: Error opening %s (%s)\n", pInfo->name,
523 			common->device_path, strerror(errno));
524 		return !Success;
525 	}
526 
527 	return Success;
528 }
529 
530 /*****************************************************************************
531  * wcmClose --
532  ****************************************************************************/
533 
wcmClose(InputInfoPtr pInfo)534 void wcmClose(InputInfoPtr pInfo)
535 {
536 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
537 
538 	DBG(1, priv, "closing device file\n");
539 
540 	if (pInfo->fd > -1 && !(pInfo->flags & XI86_SERVER_FD)) {
541 		xf86CloseSerial(pInfo->fd);
542 		pInfo->fd = -1;
543 	}
544 }
545 
546 /*****************************************************************************
547  * wcmDevOpen --
548  *    Open the physical device and init information structs.
549  ****************************************************************************/
550 
wcmDevOpen(DeviceIntPtr pWcm)551 static int wcmDevOpen(DeviceIntPtr pWcm)
552 {
553 	InputInfoPtr pInfo = (InputInfoPtr)pWcm->public.devicePrivate;
554 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
555 	WacomCommonPtr common = priv->common;
556 	WacomModelPtr model = common->wcmModel;
557 	struct stat st;
558 
559 	DBG(10, priv, "\n");
560 
561 	/* If fd management is done by the server, skip common fd handling */
562 	if (pInfo->flags & XI86_SERVER_FD)
563 		goto got_fd;
564 
565 	/* open file, if not already open */
566 	if (common->fd_refs == 0)
567 	{
568 		if ((wcmOpen (pInfo) != Success) || !common->device_path)
569 		{
570 			DBG(1, priv, "Failed to open device (fd=%d)\n", pInfo->fd);
571 			wcmClose(pInfo);
572 			return FALSE;
573 		}
574 
575 		if (fstat(pInfo->fd, &st) == -1)
576 		{
577 			/* can not access major/minor */
578 			DBG(1, priv, "stat failed (%s).\n", strerror(errno));
579 
580 			/* older systems don't support the required ioctl.
581 			 * So, we have to let it pass */
582 			common->min_maj = 0;
583 		}
584 		else
585 			common->min_maj = st.st_rdev;
586 		common->fd = pInfo->fd;
587 		common->fd_refs = 1;
588 	}
589 
590 	/* Grab the common descriptor, if it's available */
591 	if (pInfo->fd < 0)
592 	{
593 		pInfo->fd = common->fd;
594 		common->fd_refs++;
595 	}
596 
597 got_fd:
598 	/* start the tablet data */
599 	if (model->Start && (model->Start(pInfo) != Success))
600 		return !Success;
601 
602 	return TRUE;
603 }
604 
wcmReady(InputInfoPtr pInfo)605 static int wcmReady(InputInfoPtr pInfo)
606 {
607 #ifdef DEBUG
608 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
609 #endif
610 	int n = xf86WaitForInput(pInfo->fd, 0);
611 	DBG(10, priv, "%d numbers of data\n", n);
612 
613 	if (n >= 0) return n ? 1 : 0;
614 	xf86Msg(X_ERROR, "%s: select error: %s\n", pInfo->name, strerror(errno));
615 	return 0;
616 }
617 
618 /*****************************************************************************
619  * wcmDevReadInput --
620  *   Read the device on IO signal
621  ****************************************************************************/
622 
wcmDevReadInput(InputInfoPtr pInfo)623 static void wcmDevReadInput(InputInfoPtr pInfo)
624 {
625 	int loop=0;
626 	#define MAX_READ_LOOPS 10
627 
628 	/* move data until we exhaust the device */
629 	for (loop=0; loop < MAX_READ_LOOPS; ++loop)
630 	{
631 		/* verify that there is still data in pipe */
632 		if (!wcmReady(pInfo)) break;
633 
634 		/* dispatch */
635 		if (!wcmReadPacket(pInfo))
636 			break;
637 	}
638 
639 #ifdef DEBUG
640 	/* report how well we're doing */
641 	if (loop > 0)
642 	{
643 		WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
644 
645 		if (loop >= MAX_READ_LOOPS)
646 			DBG(1, priv, "Can't keep up!!!\n");
647 		else
648 			DBG(10, priv, "Read (%d)\n",loop);
649 	}
650 #endif
651 }
652 
wcmReadPacket(InputInfoPtr pInfo)653 Bool wcmReadPacket(InputInfoPtr pInfo)
654 {
655 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
656 	WacomCommonPtr common = priv->common;
657 	int len, pos, cnt, remaining;
658 
659 	DBG(10, common, "fd=%d\n", pInfo->fd);
660 
661 	remaining = sizeof(common->buffer) - common->bufpos;
662 
663 	DBG(1, common, "pos=%d remaining=%d\n", common->bufpos, remaining);
664 
665 	/* fill buffer with as much data as we can handle */
666 	len = xf86ReadSerial(pInfo->fd,
667 		common->buffer + common->bufpos, remaining);
668 
669 	if (len <= 0)
670 	{
671 		/* BSD specific code. */
672 		/* Hotplug code does not send remove dev notify because
673 		 * opened cuse dev cant be removed. */
674 		if (priv->isParent && errno == EINVAL) {
675 			WacomDevicePtr other;
676 			for (other = common->wcmDevices; other; other = other->next) {
677 				xf86Msg(X_INFO, "%s: removing automatically added device.\n",
678 					other->pInfo->name);
679 				DeleteInputDeviceRequest(other->pInfo->dev);
680 			}
681 		} else
682 		/* for all other errors, hope that the hotplugging code will
683 		 * remove the device */
684 		if (errno != EAGAIN && errno != EINTR)
685 			LogMessageVerbSigSafe(X_ERROR, 0,
686 					      "%s: Error reading wacom device : %s\n", pInfo->name, strerror(errno));
687 		if (errno == ENODEV)
688 			xf86RemoveEnabledDevice(pInfo);
689 
690 		return FALSE;
691 	}
692 
693 	/* account for new data */
694 	common->bufpos += len;
695 	DBG(10, common, "buffer has %d bytes\n", common->bufpos);
696 
697 	len = common->bufpos;
698 	pos = 0;
699 
700 	while (len > 0)
701 	{
702 		/* parse packet */
703 		cnt = common->wcmModel->Parse(pInfo, common->buffer + pos, len);
704 		if (cnt <= 0)
705 		{
706 			if (cnt < 0)
707 				DBG(1, common, "Misbehaving parser returned %d\n",cnt);
708 			break;
709 		}
710 		pos += cnt;
711 		len -= cnt;
712 	}
713 
714 	/* if half a packet remains, move it down */
715 	if (len)
716 	{
717 		DBG(7, common, "MOVE %d bytes\n", common->bufpos - pos);
718 		memmove(common->buffer,common->buffer+pos, len);
719 	}
720 
721 	common->bufpos = len;
722 
723 	return TRUE;
724 }
725 
wcmDevChangeControl(InputInfoPtr pInfo,xDeviceCtl * control)726 int wcmDevChangeControl(InputInfoPtr pInfo, xDeviceCtl * control)
727 {
728 #ifdef DEBUG
729 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
730 	DBG(3, priv, "\n");
731 #endif
732 	return Success;
733 }
734 
735 /*****************************************************************************
736  * wcmDevControlProc --
737  ****************************************************************************/
738 
wcmDevControlProc(DeviceIntPtr device,PtrCtrl * ctrl)739 static void wcmDevControlProc(DeviceIntPtr device, PtrCtrl* ctrl)
740 {
741 #ifdef DEBUG
742 	InputInfoPtr pInfo = (InputInfoPtr)device->public.devicePrivate;
743 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
744 
745 	DBG(4, priv, "called\n");
746 #endif
747 	return;
748 }
749 
750 /*****************************************************************************
751  * wcmDevClose --
752  ****************************************************************************/
753 
wcmDevClose(InputInfoPtr pInfo)754 static void wcmDevClose(InputInfoPtr pInfo)
755 {
756 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
757 	WacomCommonPtr common = priv->common;
758 
759 	/* If fd management is done by the server, skip common fd handling */
760 	if (pInfo->flags & XI86_SERVER_FD)
761 		return;
762 
763 	DBG(4, priv, "Wacom number of open devices = %d\n", common->fd_refs);
764 
765 	if (pInfo->fd >= 0)
766 	{
767 		if (!--common->fd_refs)
768 			wcmClose(pInfo);
769 		pInfo->fd = -1;
770 	}
771 }
772 
wcmEnableDisableTool(DeviceIntPtr dev,Bool enable)773 static void wcmEnableDisableTool(DeviceIntPtr dev, Bool enable)
774 {
775 	InputInfoPtr	pInfo	= dev->public.devicePrivate;
776 	WacomDevicePtr	priv	= pInfo->private;
777 	WacomToolPtr	tool	= priv->tool;
778 
779 	tool->enabled = enable;
780 }
781 
wcmEnableTool(DeviceIntPtr dev)782 static void wcmEnableTool(DeviceIntPtr dev)
783 {
784 	wcmEnableDisableTool(dev, TRUE);
785 }
wcmDisableTool(DeviceIntPtr dev)786 static void wcmDisableTool(DeviceIntPtr dev)
787 {
788 	wcmEnableDisableTool(dev, FALSE);
789 }
790 
791 /**
792  * Unlink the touch tool from the pen of the same device
793  */
wcmUnlinkTouchAndPen(InputInfoPtr pInfo)794 static void wcmUnlinkTouchAndPen(InputInfoPtr pInfo)
795 {
796 	WacomDevicePtr priv = pInfo->private;
797 	WacomCommonPtr common = priv->common;
798 	InputInfoPtr device = xf86FirstLocalDevice();
799 	WacomCommonPtr tmpcommon = NULL;
800 	WacomDevicePtr tmppriv = NULL;
801 	Bool touch_device = FALSE;
802 
803 	if (!TabletHasFeature(common, WCM_PENTOUCH))
804 		return;
805 
806 	/* Lookup to find the associated pen and touch */
807 	for (; device != NULL; device = device->next)
808 	{
809 		if (!strcmp(device->drv->driverName, "wacom"))
810 		{
811 			tmppriv = (WacomDevicePtr) device->private;
812 			tmpcommon = tmppriv->common;
813 			touch_device = (common->wcmTouchDevice ||
814 						tmpcommon->wcmTouchDevice);
815 
816 			/* skip the same tool or unlinked devices */
817 			if ((tmppriv == priv) || !touch_device)
818 				continue;
819 
820 			if (tmpcommon->tablet_id == common->tablet_id)
821 			{
822 				common->wcmTouchDevice = NULL;
823 				tmpcommon->wcmTouchDevice = NULL;
824 				common->tablet_type &= ~WCM_PENTOUCH;
825 				tmpcommon->tablet_type &= ~WCM_PENTOUCH;
826 				return;
827 			}
828 		}
829 	}
830 }
831 
832 /*****************************************************************************
833  * wcmDevProc --
834  *   Handle the initialization, etc. of a wacom tablet. Called by the server
835  *   once with DEVICE_INIT when the device becomes available, then
836  *   DEVICE_ON/DEVICE_OFF possibly multiple times as the device is enabled
837  *   and disabled. DEVICE_CLOSE is called before removal of the device.
838  ****************************************************************************/
839 
wcmDevProc(DeviceIntPtr pWcm,int what)840 static int wcmDevProc(DeviceIntPtr pWcm, int what)
841 {
842 	InputInfoPtr pInfo = (InputInfoPtr)pWcm->public.devicePrivate;
843 	WacomDevicePtr priv = (WacomDevicePtr)pInfo->private;
844 	Status rc = !Success;
845 
846 	DBG(2, priv, "BEGIN dev=%p priv=%p "
847 			"type=%s flags=%d fd=%d what=%s\n",
848 			(void *)pWcm, (void *)priv,
849 			pInfo->type_name,
850 			priv->flags, pInfo ? pInfo->fd : -1,
851 			(what == DEVICE_INIT) ? "INIT" :
852 			(what == DEVICE_OFF) ? "OFF" :
853 			(what == DEVICE_ON) ? "ON" :
854 			(what == DEVICE_CLOSE) ? "CLOSE" : "???");
855 
856 	switch (what)
857 	{
858 		case DEVICE_INIT:
859 			if (!wcmDevInit(pWcm))
860 				goto out;
861 			break;
862 
863 		case DEVICE_ON:
864 			if (!wcmDevOpen(pWcm))
865 				goto out;
866 			wcmEnableTool(pWcm);
867 			xf86AddEnabledDevice(pInfo);
868 			pWcm->public.on = TRUE;
869 			break;
870 
871 		case DEVICE_OFF:
872 			TimerCancel(priv->tap_timer);
873 			TimerCancel(priv->serial_timer);
874 			TimerCancel(priv->touch_timer);
875 			wcmDisableTool(pWcm);
876 			wcmUnlinkTouchAndPen(pInfo);
877 			if (pInfo->fd >= 0)
878 			{
879 				xf86RemoveEnabledDevice(pInfo);
880 				wcmDevClose(pInfo);
881 			}
882 			pWcm->public.on = FALSE;
883 			break;
884 		case DEVICE_CLOSE:
885 			break;
886 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) * 100 + GET_ABI_MINOR(ABI_XINPUT_VERSION) >= 1901
887 		case DEVICE_ABORT:
888 			break;
889 #endif
890 		default:
891 			xf86Msg(X_ERROR, "%s: invalid mode=%d. This is an X server bug.\n",
892 				pInfo->name, what);
893 			goto out;
894 	} /* end switch */
895 
896 	rc = Success;
897 
898 out:
899 	if (rc != Success)
900 		DBG(1, priv, "Failed during %d\n", what);
901 	return rc;
902 }
903 
904 /* vim: set noexpandtab tabstop=8 shiftwidth=8: */
905