1 /*
2  * Copyright © 2011 Red Hat, Inc.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software
5  * and its documentation for any purpose is hereby granted without
6  * fee, provided that the above copyright notice appear in all copies
7  * and that both that copyright notice and this permission notice
8  * appear in supporting documentation, and that the name of Red Hat
9  * not be used in advertising or publicity pertaining to distribution
10  * of the software without specific, written prior permission.  Red
11  * Hat makes no representations about the suitability of this software
12  * for any purpose.  It is provided "as is" without express or implied
13  * warranty.
14  *
15  * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17  * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors:
24  *	Peter Hutterer (peter.hutterer@redhat.com)
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include "libwacomint.h"
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <gudev/gudev.h>
38 
39 #include <linux/input-event-codes.h>
40 
41 static const WacomDevice *
libwacom_get_device(const WacomDeviceDatabase * db,const char * match)42 libwacom_get_device(const WacomDeviceDatabase *db, const char *match)
43 {
44 	return (WacomDevice *) g_hash_table_lookup (db->device_ht, match);
45 }
46 
47 static gboolean
is_tablet(GUdevDevice * device)48 is_tablet (GUdevDevice *device)
49 {
50 	return g_udev_device_get_property_as_boolean (device, "ID_INPUT_TABLET");
51 }
52 
53 static gboolean
is_touchpad(GUdevDevice * device)54 is_touchpad (GUdevDevice *device)
55 {
56 	return g_udev_device_get_property_as_boolean (device, "ID_INPUT_TOUCHPAD");
57 }
58 
59 
60 static gboolean
is_tablet_or_touchpad(GUdevDevice * device)61 is_tablet_or_touchpad (GUdevDevice *device)
62 {
63 	return is_touchpad (device) || is_tablet (device);
64 }
65 
66 /* Overriding SUBSYSTEM isn't allowed in udev (works sometimes, but not
67  * always). For evemu devices we need to set custom properties to make them
68  * detected by libwacom.
69  */
70 static char *
get_uinput_subsystem(GUdevDevice * device)71 get_uinput_subsystem (GUdevDevice *device)
72 {
73 	const char *bus_str;
74 	GUdevDevice *parent;
75 
76 
77 	bus_str = NULL;
78 	parent = g_object_ref (device);
79 
80 	while (parent && !g_udev_device_get_property_as_boolean (parent, "UINPUT_DEVICE")) {
81 		GUdevDevice *old_parent = parent;
82 		parent = g_udev_device_get_parent (old_parent);
83 		g_object_unref (old_parent);
84 	}
85 
86 	if (parent) {
87 		bus_str = g_udev_device_get_property (parent, "UINPUT_SUBSYSTEM");
88 		g_object_unref (parent);
89 	}
90 
91 	return bus_str ? g_strdup (bus_str) : NULL;
92 }
93 
94 static gboolean
get_bus_vid_pid(GUdevDevice * device,WacomBusType * bus,int * vendor_id,int * product_id,WacomError * error)95 get_bus_vid_pid (GUdevDevice  *device,
96 		 WacomBusType *bus,
97 		 int          *vendor_id,
98 		 int          *product_id,
99 		 WacomError   *error)
100 {
101 	GUdevDevice *parent;
102 	const char *product_str;
103 	gchar **splitted_product = NULL;
104 	unsigned int bus_id;
105 	gboolean retval = FALSE;
106 
107 	/* Parse that:
108 	 * E: PRODUCT=5/56a/81/100
109 	 * into:
110 	 * vendor 0x56a
111 	 * product 0x81 */
112 	parent = g_object_ref (device);
113 	product_str = g_udev_device_get_property (device, "PRODUCT");
114 
115 	while (!product_str && parent) {
116 		GUdevDevice *old_parent = parent;
117 		parent = g_udev_device_get_parent (old_parent);
118 		if (parent)
119 			product_str = g_udev_device_get_property (parent, "PRODUCT");
120 		g_object_unref (old_parent);
121 	}
122 
123 	if (!product_str)
124 		/* PRODUCT not found, hoping the old method will work */
125 		goto out;
126 
127 	splitted_product = g_strsplit (product_str, "/", 4);
128 	if (g_strv_length (splitted_product) != 4) {
129 		libwacom_error_set(error, WERROR_UNKNOWN_MODEL, "Unable to parse model identification");
130 		goto out;
131 	}
132 
133 	bus_id = (int)strtoul (splitted_product[0], NULL, 16);
134 	*vendor_id = (int)strtol (splitted_product[1], NULL, 16);
135 	*product_id = (int)strtol (splitted_product[2], NULL, 16);
136 
137 	switch (bus_id) {
138 	case 3:
139 		*bus = WBUSTYPE_USB;
140 		retval = TRUE;
141 		break;
142 	case 5:
143 		*bus = WBUSTYPE_BLUETOOTH;
144 		retval = TRUE;
145 		break;
146 	case 24:
147 		*bus = WBUSTYPE_I2C;
148 		retval = TRUE;
149 		break;
150 	}
151 
152 out:
153 	if (splitted_product)
154 		g_strfreev (splitted_product);
155 	if (parent)
156 		g_object_unref (parent);
157 	return retval;
158 }
159 
160 static char *
get_bus(GUdevDevice * device)161 get_bus (GUdevDevice *device)
162 {
163 	const char *subsystem;
164 	char *bus_str;
165 	GUdevDevice *parent;
166 
167 	bus_str = get_uinput_subsystem (device);
168 	if (bus_str)
169 		return bus_str;
170 
171 	subsystem = g_udev_device_get_subsystem (device);
172 	parent = g_object_ref (device);
173 
174 	while (parent && subsystem &&
175 	       (streq(subsystem, "input") || streq (subsystem, "hid"))) {
176 		GUdevDevice *old_parent = parent;
177 		parent = g_udev_device_get_parent (old_parent);
178 		if (parent)
179 			subsystem = g_udev_device_get_subsystem (parent);
180 		g_object_unref (old_parent);
181 	}
182 
183 	if (parent) {
184 		if (subsystem && (streq(subsystem, "tty") || streq(subsystem, "serio")))
185 			bus_str = g_strdup ("serial");
186 		else
187 			bus_str = g_strdup (subsystem);
188 
189 		g_object_unref (parent);
190 	} else
191 		bus_str = strdup("unknown");
192 
193 	return bus_str;
194 }
195 
196 static gboolean
get_device_info(const char * path,int * vendor_id,int * product_id,char ** name,WacomBusType * bus,WacomIntegrationFlags * integration_flags,WacomError * error)197 get_device_info (const char            *path,
198 		 int                   *vendor_id,
199 		 int                   *product_id,
200 		 char                 **name,
201 		 WacomBusType          *bus,
202 		 WacomIntegrationFlags *integration_flags,
203 		 WacomError            *error)
204 {
205 	GUdevClient *client;
206 	GUdevDevice *device;
207 	const char * const subsystems[] = { "input", NULL };
208 	gboolean retval;
209 	char *bus_str;
210 	const char *devname;
211 
212 #if NEED_G_TYPE_INIT
213 	g_type_init();
214 #endif
215 
216 	retval = FALSE;
217 	/* The integration flags from device info are unset by default */
218 	*integration_flags = WACOM_DEVICE_INTEGRATED_UNSET;
219 	*name = NULL;
220 	bus_str = NULL;
221 	client = g_udev_client_new (subsystems);
222 	device = g_udev_client_query_by_device_file (client, path);
223 	if (device == NULL) {
224 		libwacom_error_set(error, WERROR_INVALID_PATH, "Could not find device '%s' in udev", path);
225 		goto out;
226 	}
227 
228 	/* Touchpads are only for the "Finger" part of Bamboo devices */
229 	if (!is_tablet_or_touchpad(device)) {
230 		GUdevDevice *parent;
231 
232 		parent = g_udev_device_get_parent(device);
233 		if (!parent || !is_tablet_or_touchpad(parent)) {
234 			libwacom_error_set(error, WERROR_INVALID_PATH, "Device '%s' is not a tablet", path);
235 			g_object_unref (parent);
236 			goto out;
237 		}
238 		g_object_unref (parent);
239 	}
240 
241 	/* Is the device integrated in display? */
242 	devname = g_udev_device_get_name (device);
243 	if (devname != NULL) {
244 		char *sysfs_path, *contents;
245 
246 		sysfs_path = g_build_filename ("/sys/class/input", devname, "device/properties", NULL);
247 		if (g_file_get_contents (sysfs_path, &contents, NULL, NULL)) {
248 			int flag;
249 
250 			flag = atoi(contents);
251 			flag &= (1 << INPUT_PROP_DIRECT) | (1 << INPUT_PROP_POINTER);
252 			/*
253 			 * To ensure we are dealing with a screen tablet, need
254 			 * to check that it has DIRECT and non-POINTER (DIRECT
255 			 * alone is not sufficient since it's set for drawing
256 			 * tablets as well)
257 			 */
258 			if (flag == (1 << INPUT_PROP_DIRECT))
259 				*integration_flags = WACOM_DEVICE_INTEGRATED_DISPLAY;
260 			else
261 				*integration_flags = WACOM_DEVICE_INTEGRATED_NONE;
262 
263 			g_free (contents);
264 		}
265 		g_free (sysfs_path);
266 	}
267 
268 	*name = g_strdup (g_udev_device_get_sysfs_attr (device, "name"));
269 	/* Try getting the name from the parent if that fails */
270 	if (*name == NULL) {
271 		GUdevDevice *parent;
272 
273 		parent = g_udev_device_get_parent (device);
274 		if (!parent)
275 			goto out;
276 		*name = g_strdup (g_udev_device_get_sysfs_attr (parent, "name"));
277 		g_object_unref (parent);
278 	}
279 
280 	/* Parse the PRODUCT attribute (for Bluetooth, USB, I2C) */
281 	retval = get_bus_vid_pid (device, bus, vendor_id, product_id, error);
282 	if (retval)
283 		goto out;
284 
285 	bus_str = get_bus (device);
286 	*bus = bus_from_str (bus_str);
287 
288 	if (*bus == WBUSTYPE_SERIAL) {
289 		if (is_touchpad (device))
290 			goto out;
291 
292 		/* The serial bus uses 0:0 as the vid/pid */
293 		*vendor_id = 0;
294 		*product_id = 0;
295 		retval = TRUE;
296 	} else {
297 		libwacom_error_set(error, WERROR_UNKNOWN_MODEL, "Unsupported bus '%s'", bus_str);
298 	}
299 
300 out:
301 	if (bus_str != NULL)
302 		g_free (bus_str);
303 	if (retval == FALSE)
304 		g_free (*name);
305 	if (device != NULL)
306 		g_object_unref (device);
307 	if (client != NULL)
308 		g_object_unref (client);
309 	return retval;
310 }
311 
312 static WacomDevice *
libwacom_copy(const WacomDevice * device)313 libwacom_copy(const WacomDevice *device)
314 {
315 	WacomDevice *d;
316 	int i;
317 
318 	d = g_new0 (WacomDevice, 1);
319 	g_atomic_int_inc(&d->refcnt);
320 	d->name = g_strdup (device->name);
321 	d->model_name = g_strdup (device->model_name);
322 	d->width = device->width;
323 	d->height = device->height;
324 	d->integration_flags = device->integration_flags;
325 	d->layout = g_strdup(device->layout);
326 	d->nmatches = device->nmatches;
327 	d->matches = g_malloc((d->nmatches + 1) * sizeof(WacomMatch*));
328 	for (i = 0; i < d->nmatches; i++)
329 		d->matches[i] = libwacom_match_ref(device->matches[i]);
330 	d->matches[d->nmatches] = NULL;
331 	d->match = device->match;
332 	if (device->paired)
333 		d->paired = libwacom_match_ref(device->paired);
334 	d->cls = device->cls;
335 	d->num_strips = device->num_strips;
336 	d->features = device->features;
337 	d->strips_num_modes = device->strips_num_modes;
338 	d->ring_num_modes = device->ring_num_modes;
339 	d->ring2_num_modes = device->ring2_num_modes;
340 	d->num_styli = device->num_styli;
341 	d->supported_styli = g_memdup (device->supported_styli, sizeof(int) * device->num_styli);
342 	d->num_leds = device->num_leds;
343 	d->status_leds = g_memdup (device->status_leds, sizeof(WacomStatusLEDs) * device->num_leds);
344 	d->num_buttons = device->num_buttons;
345 	d->buttons = g_memdup (device->buttons, sizeof(WacomButtonFlags) * device->num_buttons);
346 	d->button_codes = g_memdup (device->button_codes, sizeof(int) * device->num_buttons);
347 	return d;
348 }
349 
350 
351 static int
compare_matches(const WacomDevice * a,const WacomDevice * b)352 compare_matches(const WacomDevice *a, const WacomDevice *b)
353 {
354 	const WacomMatch **ma, **mb, **match_a, **match_b;
355 
356 	ma = libwacom_get_matches(a);
357 	mb = libwacom_get_matches(b);
358 
359 	for (match_a = ma; *match_a; match_a++) {
360 		int found = 0;
361 		for (match_b = mb; !found && *match_b; match_b++) {
362 			if (streq((*match_a)->match, (*match_b)->match))
363 				found = 1;
364 		}
365 		if (!found)
366 			return 1;
367 	}
368 
369 	return 0;
370 }
371 
372 /* Compare layouts based on file name, stripping the full path */
373 static gboolean
libwacom_same_layouts(const WacomDevice * a,const WacomDevice * b)374 libwacom_same_layouts (const WacomDevice *a, const WacomDevice *b)
375 {
376 	gchar *file1, *file2;
377 	gboolean rc;
378 
379 	/* Conveniently handle the null case */
380 	if (a->layout == b->layout)
381 		return TRUE;
382 
383 	file1 = NULL;
384 	file2 = NULL;
385 	if (a->layout != NULL)
386 		file1 = g_path_get_basename (a->layout);
387 	if (b->layout != NULL)
388 		file2 = g_path_get_basename (b->layout);
389 
390 	rc = (g_strcmp0 (file1, file2) == 0);
391 
392 	g_free (file1);
393 	g_free (file2);
394 
395 	return rc;
396 }
397 
398 LIBWACOM_EXPORT int
libwacom_compare(const WacomDevice * a,const WacomDevice * b,WacomCompareFlags flags)399 libwacom_compare(const WacomDevice *a, const WacomDevice *b, WacomCompareFlags flags)
400 {
401 	g_return_val_if_fail(a || b, 0);
402 
403 	if (!a || !b)
404 		return 1;
405 
406 	if (!streq(a->name, b->name))
407 		return 1;
408 
409 	if (a->width != b->width || a->height != b->height)
410 		return 1;
411 
412 	if (!libwacom_same_layouts (a, b))
413 		return 1;
414 
415 	if (a->integration_flags != b->integration_flags)
416 		return 1;
417 
418 	if (a->cls != b->cls)
419 		return 1;
420 
421 	if (a->num_strips != b->num_strips)
422 		return 1;
423 
424 	if (a->features != b->features)
425 		return 1;
426 
427 	if (a->strips_num_modes != b->strips_num_modes)
428 		return 1;
429 
430 	if (a->ring_num_modes != b->ring_num_modes)
431 		return 1;
432 
433 	if (a->ring2_num_modes != b->ring2_num_modes)
434 		return 1;
435 
436 	if (a->num_buttons != b->num_buttons)
437 		return 1;
438 
439 	if (a->num_styli != b->num_styli)
440 		return 1;
441 
442 	if (memcmp(a->supported_styli, b->supported_styli, sizeof(int) * a->num_styli) != 0)
443 		return 1;
444 
445 	if (a->num_leds != b->num_leds)
446 		return 1;
447 
448 	if (memcmp(a->status_leds, b->status_leds, sizeof(WacomStatusLEDs) * a->num_leds) != 0)
449 		return 1;
450 
451 	if (memcmp(a->buttons, b->buttons, sizeof(WacomButtonFlags) * a->num_buttons) != 0)
452 		return 1;
453 
454 	if (memcmp(a->button_codes, b->button_codes, sizeof(int) * a->num_buttons) != 0)
455 		return 1;
456 
457 	if ((a->paired == NULL && b->paired != NULL) ||
458 	    (a->paired != NULL && b->paired == NULL) ||
459 	    (a->paired && b->paired && !streq(a->paired->match, b->paired->match)))
460 		return 1;
461 
462 	if ((flags & WCOMPARE_MATCHES) && compare_matches(a, b) != 0)
463 		return 1;
464 	else if (!streq(a->matches[a->match]->match, b->matches[b->match]->match))
465 		return 1;
466 
467 	return 0;
468 }
469 
470 static const WacomDevice *
libwacom_new(const WacomDeviceDatabase * db,const char * name,int vendor_id,int product_id,WacomBusType bus,WacomError * error)471 libwacom_new (const WacomDeviceDatabase *db, const char *name, int vendor_id, int product_id, WacomBusType bus, WacomError *error)
472 {
473 	const WacomDevice *device;
474 	char *match;
475 
476 	if (!db) {
477 		libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
478 		return NULL;
479 	}
480 
481 	match = make_match_string(name, bus, vendor_id, product_id);
482 	device = libwacom_get_device(db, match);
483 	g_free (match);
484 
485 	return device;
486 }
487 
488 LIBWACOM_EXPORT WacomDevice*
libwacom_new_from_path(const WacomDeviceDatabase * db,const char * path,WacomFallbackFlags fallback,WacomError * error)489 libwacom_new_from_path(const WacomDeviceDatabase *db, const char *path, WacomFallbackFlags fallback, WacomError *error)
490 {
491 	int vendor_id, product_id;
492 	WacomBusType bus;
493 	const WacomDevice *device;
494 	WacomDevice *ret = NULL;
495 	WacomIntegrationFlags integration_flags;
496 	char *name, *match_name;
497 	WacomMatch *match;
498 
499 	switch (fallback) {
500 		case WFALLBACK_NONE:
501 		case WFALLBACK_GENERIC:
502 			break;
503 		default:
504 			libwacom_error_set(error, WERROR_BUG_CALLER, "invalid fallback flags");
505 			return NULL;
506 	}
507 
508 	if (!db) {
509 		libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
510 		return NULL;
511 	}
512 
513 	if (!path) {
514 		libwacom_error_set(error, WERROR_INVALID_PATH, "path is NULL");
515 		return NULL;
516 	}
517 
518 	if (!get_device_info (path, &vendor_id, &product_id, &name, &bus, &integration_flags, error))
519 		return NULL;
520 
521 	match_name = name;
522 	device = libwacom_new (db, match_name, vendor_id, product_id, bus, error);
523 	if (device == NULL) {
524 		match_name = NULL;
525 		device = libwacom_new (db, match_name, vendor_id, product_id, bus, error);
526 	}
527 	if (device != NULL)
528 		ret = libwacom_copy(device);
529 	else if (fallback == WFALLBACK_NONE)
530 		goto bail;
531 
532 	if (device == NULL && fallback == WFALLBACK_GENERIC) {
533 		device = libwacom_get_device(db, "generic");
534 		if (device == NULL)
535 			goto bail;
536 
537 		ret = libwacom_copy(device);
538 
539 		if (name != NULL) {
540 			g_free (ret->name);
541 			ret->name = g_strdup(name);
542 		}
543 	}
544 
545 	/* for multiple-match devices, set to the one we requested */
546 	match = libwacom_match_new(match_name, bus, vendor_id, product_id);
547 	libwacom_add_match(ret, match);
548 	libwacom_match_unref(match);
549 
550 	if (device) {
551 		/* if unset, use the kernel flags. Could be unset as well. */
552 		if (ret->integration_flags == WACOM_DEVICE_INTEGRATED_UNSET)
553 			ret->integration_flags = integration_flags;
554 
555 		g_free (name);
556 
557 		return ret;
558 	}
559 
560 bail:
561 	g_free (name);
562 	libwacom_error_set(error, WERROR_UNKNOWN_MODEL, NULL);
563 	return NULL;
564 }
565 
566 LIBWACOM_EXPORT WacomDevice*
libwacom_new_from_usbid(const WacomDeviceDatabase * db,int vendor_id,int product_id,WacomError * error)567 libwacom_new_from_usbid(const WacomDeviceDatabase *db, int vendor_id, int product_id, WacomError *error)
568 {
569 	const WacomDevice *device;
570 
571 	if (!db) {
572 		libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
573 		return NULL;
574 	}
575 
576 	device = libwacom_new(db, NULL, vendor_id, product_id, WBUSTYPE_USB, error);
577 
578 	if (device)
579 		return libwacom_copy(device);
580 
581 	libwacom_error_set(error, WERROR_UNKNOWN_MODEL, NULL);
582 	return NULL;
583 }
584 
585 LIBWACOM_EXPORT WacomDevice*
libwacom_new_from_name(const WacomDeviceDatabase * db,const char * name,WacomError * error)586 libwacom_new_from_name(const WacomDeviceDatabase *db, const char *name, WacomError *error)
587 {
588 	const WacomDevice *device;
589 	GList *keys, *l;
590 
591 	if (!db) {
592 		libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
593 		return NULL;
594 	}
595 
596 	g_return_val_if_fail(name != NULL, NULL);
597 
598 	device = NULL;
599 	keys = g_hash_table_get_values (db->device_ht);
600 	for (l = keys; l; l = l->next) {
601 		WacomDevice *d = l->data;
602 
603 		if (streq(d->name, name)) {
604 			device = d;
605 			break;
606 		}
607 	}
608 	g_list_free (keys);
609 
610 	if (device)
611 		return libwacom_copy(device);
612 
613 	libwacom_error_set(error, WERROR_UNKNOWN_MODEL, NULL);
614 	return NULL;
615 }
616 
print_styli_for_device(int fd,const WacomDevice * device)617 static void print_styli_for_device (int fd, const WacomDevice *device)
618 {
619 	int nstyli;
620 	const int *styli;
621 	int i;
622 	unsigned idx = 0;
623 	char buf[1024] = {0};
624 
625 	if (!libwacom_has_stylus(device))
626 		return;
627 
628 	styli = libwacom_get_supported_styli(device, &nstyli);
629 
630 	for (i = 0; i < nstyli; i++) {
631 		/* 20 digits for a stylus are enough, right */
632 		assert(idx < sizeof(buf) - 20);
633 
634 		idx += snprintf(buf + idx, 20, "%#x;", styli[i]);
635 	}
636 
637 	dprintf(fd, "Styli=%s\n", buf);
638 }
639 
print_layout_for_device(int fd,const WacomDevice * device)640 static void print_layout_for_device (int fd, const WacomDevice *device)
641 {
642 	const char *layout_filename;
643 	gchar      *base_name;
644 
645 	layout_filename = libwacom_get_layout_filename(device);
646 	if (layout_filename) {
647 		base_name = g_path_get_basename (layout_filename);
648 		dprintf(fd, "Layout=%s\n", base_name);
649 		g_free (base_name);
650 	}
651 }
652 
print_supported_leds(int fd,const WacomDevice * device)653 static void print_supported_leds (int fd, const WacomDevice *device)
654 {
655 	char *leds_name[] = {
656 		"Ring;",
657 		"Ring2;",
658 		"Touchstrip;",
659 		"Touchstrip2;"
660 	};
661 	int num_leds;
662 	const WacomStatusLEDs *status_leds;
663 	char buf[256] = {0};
664 	bool have_led = false;
665 
666 	status_leds = libwacom_get_status_leds(device, &num_leds);
667 
668 	snprintf(buf, sizeof(buf), "%s%s%s%s",
669 		 num_leds > 0 ? leds_name[status_leds[0]] : "",
670 		 num_leds > 1 ? leds_name[status_leds[1]] : "",
671 		 num_leds > 2 ? leds_name[status_leds[2]] : "",
672 		 num_leds > 3 ? leds_name[status_leds[3]] : "");
673 	have_led = num_leds > 0;
674 
675 	dprintf(fd, "%sStatusLEDs=%s\n", have_led ? "" : "# ", buf);
676 }
677 
print_button_flag_if(int fd,const WacomDevice * device,const char * label,int flag)678 static void print_button_flag_if(int fd, const WacomDevice *device, const char *label, int flag)
679 {
680 	int nbuttons = libwacom_get_num_buttons(device);
681 	char buf[nbuttons * 2 + 1];
682 	int idx = 0;
683 	char b;
684 	bool have_flag = false;
685 
686 	for (b = 'A'; b < 'A' + nbuttons; b++) {
687 		if (libwacom_get_button_flag(device, b) & flag) {
688 			buf[idx++] = b;
689 			buf[idx++] = ';';
690 			have_flag = true;
691 		}
692 	}
693 	buf[idx] = '\0';
694 	dprintf(fd, "%s%s=%s\n", have_flag ? "" : "# ", label, buf);
695 }
696 
print_button_evdev_codes(int fd,const WacomDevice * device)697 static void print_button_evdev_codes(int fd, const WacomDevice *device)
698 {
699 	int nbuttons = libwacom_get_num_buttons(device);
700 	char b;
701 	char buf[1024] = {0};
702 	unsigned idx = 0;
703 
704 	for (b = 'A'; b < 'A' + nbuttons; b++) {
705 		assert(idx < sizeof(buf) - 30);
706 		idx += snprintf(buf + idx, 30, "0x%x;",
707 				libwacom_get_button_evdev_code(device, b));
708 	}
709 	dprintf(fd, "EvdevCodes=%s\n", buf);
710 }
711 
print_buttons_for_device(int fd,const WacomDevice * device)712 static void print_buttons_for_device (int fd, const WacomDevice *device)
713 {
714 	int nbuttons = libwacom_get_num_buttons(device);
715 
716 	if (nbuttons == 0)
717 		return;
718 
719 	dprintf(fd, "[Buttons]\n");
720 
721 	print_button_flag_if(fd, device, "Left", WACOM_BUTTON_POSITION_LEFT);
722 	print_button_flag_if(fd, device, "Right", WACOM_BUTTON_POSITION_RIGHT);
723 	print_button_flag_if(fd, device, "Top", WACOM_BUTTON_POSITION_TOP);
724 	print_button_flag_if(fd, device, "Bottom", WACOM_BUTTON_POSITION_BOTTOM);
725 	print_button_flag_if(fd, device, "Touchstrip", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH);
726 	print_button_flag_if(fd, device, "Touchstrip2", WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH);
727 	print_button_flag_if(fd, device, "OLEDs", WACOM_BUTTON_OLED);
728 	print_button_flag_if(fd, device, "Ring", WACOM_BUTTON_RING_MODESWITCH);
729 	print_button_flag_if(fd, device, "Ring2", WACOM_BUTTON_RING2_MODESWITCH);
730 	print_button_evdev_codes(fd, device);
731 	dprintf(fd, "RingNumModes=%d\n", libwacom_get_ring_num_modes(device));
732 	dprintf(fd, "Ring2NumModes=%d\n", libwacom_get_ring2_num_modes(device));
733 	dprintf(fd, "StripsNumModes=%d\n", libwacom_get_strips_num_modes(device));
734 
735 	dprintf(fd, "\n");
736 }
737 
print_integrated_flags_for_device(int fd,const WacomDevice * device)738 static void print_integrated_flags_for_device (int fd, const WacomDevice *device)
739 {
740 	/*
741 	 * If flag is WACOM_DEVICE_INTEGRATED_UNSET, the info is not provided
742 	 * by the tablet database but deduced otherwise (e.g. from sysfs device
743 	 * properties on Linux)
744 	 */
745 	if (device->integration_flags == WACOM_DEVICE_INTEGRATED_UNSET)
746 		return;
747 	dprintf(fd, "IntegratedIn=");
748 	if (device->integration_flags & WACOM_DEVICE_INTEGRATED_DISPLAY)
749 		dprintf(fd, "Display;");
750 	if (device->integration_flags & WACOM_DEVICE_INTEGRATED_SYSTEM)
751 		dprintf(fd, "System;");
752 	dprintf(fd, "\n");
753 }
754 
print_match(int fd,const WacomMatch * match)755 static void print_match(int fd, const WacomMatch *match)
756 {
757 	const char  *name       = libwacom_match_get_name(match);
758 	WacomBusType type	= libwacom_match_get_bustype(match);
759 	int          vendor     = libwacom_match_get_vendor_id(match);
760 	int          product    = libwacom_match_get_product_id(match);
761 	const char  *bus_name;
762 
763 	switch(type) {
764 		case WBUSTYPE_BLUETOOTH:	bus_name = "bluetooth";	break;
765 		case WBUSTYPE_USB:		bus_name = "usb";	break;
766 		case WBUSTYPE_SERIAL:		bus_name = "serial";	break;
767 		case WBUSTYPE_I2C:		bus_name = "i2c";	break;
768 		case WBUSTYPE_UNKNOWN:		bus_name = "unknown";	break;
769 		default:			g_assert_not_reached(); break;
770 	}
771 	dprintf(fd, "%s:%04x:%04x", bus_name, vendor, product);
772 	if (name)
773 		dprintf(fd, ":%s", name);
774 	dprintf(fd, ";");
775 }
776 
777 LIBWACOM_EXPORT void
libwacom_print_device_description(int fd,const WacomDevice * device)778 libwacom_print_device_description(int fd, const WacomDevice *device)
779 {
780 	const WacomMatch **match;
781 	WacomClass class;
782 	const char *class_name;
783 
784 	class  = device->cls;
785 	switch(class) {
786 		case WCLASS_UNKNOWN:	class_name = "Unknown";	break;
787 		case WCLASS_INTUOS3:	class_name = "Intuos3";	break;
788 		case WCLASS_INTUOS4:	class_name = "Intuos4";	break;
789 		case WCLASS_INTUOS5:	class_name = "Intuos5";	break;
790 		case WCLASS_CINTIQ:	class_name = "Cintiq";	break;
791 		case WCLASS_BAMBOO:	class_name = "Bamboo";	break;
792 		case WCLASS_GRAPHIRE:	class_name = "Graphire";break;
793 		case WCLASS_ISDV4:	class_name = "ISDV4";	break;
794 		case WCLASS_INTUOS:	class_name = "Intuos";	break;
795 		case WCLASS_INTUOS2:	class_name = "Intuos2";	break;
796 		case WCLASS_PEN_DISPLAYS:	class_name = "PenDisplay";	break;
797 		case WCLASS_REMOTE:	class_name = "Remote";	break;
798 		default:		g_assert_not_reached(); break;
799 	}
800 
801 	dprintf(fd, "[Device]\n");
802 	dprintf(fd, "Name=%s\n", libwacom_get_name(device));
803 	dprintf(fd, "ModelName=%s\n", libwacom_get_model_name(device) ? libwacom_get_model_name(device) : "");
804 	dprintf(fd, "DeviceMatch=");
805 	for (match = libwacom_get_matches(device); *match; match++)
806 		print_match(fd, *match);
807 	dprintf(fd, "\n");
808 
809 	if (libwacom_get_paired_device(device)) {
810 		dprintf(fd, "PairedID=");
811 		print_match(fd, libwacom_get_paired_device(device));
812 		dprintf(fd, "\n");
813 	}
814 
815 	dprintf(fd, "Class=%s\n",		class_name);
816 	dprintf(fd, "Width=%d\n",		libwacom_get_width(device));
817 	dprintf(fd, "Height=%d\n",		libwacom_get_height(device));
818 	print_integrated_flags_for_device(fd, device);
819 	print_layout_for_device(fd, device);
820 	print_styli_for_device(fd, device);
821 	dprintf(fd, "\n");
822 
823 	dprintf(fd, "[Features]\n");
824 	dprintf(fd, "Reversible=%s\n", libwacom_is_reversible(device)	? "true" : "false");
825 	dprintf(fd, "Stylus=%s\n",	 libwacom_has_stylus(device)	? "true" : "false");
826 	dprintf(fd, "Ring=%s\n",	 libwacom_has_ring(device)	? "true" : "false");
827 	dprintf(fd, "Ring2=%s\n",	 libwacom_has_ring2(device)	? "true" : "false");
828 	dprintf(fd, "Touch=%s\n",	 libwacom_has_touch(device)	? "true" : "false");
829 	dprintf(fd, "TouchSwitch=%s\n",	libwacom_has_touchswitch(device)? "true" : "false");
830 	print_supported_leds(fd, device);
831 
832 	dprintf(fd, "NumStrips=%d\n",	libwacom_get_num_strips(device));
833 	dprintf(fd, "Buttons=%d\n",		libwacom_get_num_buttons(device));
834 	dprintf(fd, "\n");
835 
836 	print_buttons_for_device(fd, device);
837 }
838 
839 WacomDevice *
libwacom_ref(WacomDevice * device)840 libwacom_ref(WacomDevice *device)
841 {
842 	assert(device->refcnt >= 1);
843 
844 	g_atomic_int_inc(&device->refcnt);
845 	return device;
846 }
847 
848 WacomDevice *
libwacom_unref(WacomDevice * device)849 libwacom_unref(WacomDevice *device)
850 {
851 	int i;
852 
853 	if (device == NULL)
854 		return NULL;
855 
856 	assert(device->refcnt >= 1);
857 
858 	if (!g_atomic_int_dec_and_test(&device->refcnt))
859 		return NULL;
860 
861 	g_free (device->name);
862 	g_free (device->model_name);
863 	g_free (device->layout);
864 	if (device->paired)
865 		libwacom_match_unref(device->paired);
866 	for (i = 0; i < device->nmatches; i++)
867 		libwacom_match_unref(device->matches[i]);
868 	g_free (device->matches);
869 	g_free (device->supported_styli);
870 	g_free (device->status_leds);
871 	g_free (device->buttons);
872 	g_free (device->button_codes);
873 	g_free (device);
874 
875 	return NULL;
876 }
877 
878 LIBWACOM_EXPORT void
libwacom_destroy(WacomDevice * device)879 libwacom_destroy(WacomDevice *device)
880 {
881 	libwacom_unref(device);
882 }
883 
884 WacomMatch*
libwacom_match_ref(WacomMatch * match)885 libwacom_match_ref(WacomMatch *match)
886 {
887 	g_atomic_int_inc(&match->refcnt);
888 	return match;
889 }
890 
891 WacomMatch*
libwacom_match_unref(WacomMatch * match)892 libwacom_match_unref(WacomMatch *match)
893 {
894 	if (!g_atomic_int_dec_and_test(&match->refcnt))
895 		return NULL;
896 
897 	g_free (match->match);
898 	g_free (match->name);
899 	g_free (match);
900 
901 	return NULL;
902 }
903 
904 WacomMatch*
libwacom_match_new(const char * name,WacomBusType bus,int vendor_id,int product_id)905 libwacom_match_new(const char *name, WacomBusType bus, int vendor_id, int product_id)
906 {
907 	WacomMatch *match;
908 	char *newmatch;
909 
910 	match = g_malloc(sizeof(*match));
911 	match->refcnt = 1;
912 	if (name == NULL && bus == WBUSTYPE_UNKNOWN && vendor_id == 0 && product_id == 0)
913 		newmatch = g_strdup("generic");
914 	else
915 		newmatch = make_match_string(name, bus, vendor_id, product_id);
916 
917 	match->match = newmatch;
918 	match->name = g_strdup(name);
919 	match->bus = bus;
920 	match->vendor_id = vendor_id;
921 	match->product_id = product_id;
922 
923 	return match;
924 }
925 
926 void
libwacom_add_match(WacomDevice * device,WacomMatch * newmatch)927 libwacom_add_match(WacomDevice *device, WacomMatch *newmatch)
928 {
929 	int i;
930 
931 	for (i = 0; i < device->nmatches; i++) {
932 		const char *matchstr = libwacom_match_get_match_string(device->matches[i]);
933 		if (streq(matchstr, newmatch->match)) {
934 			device->match = i;
935 			return;
936 		}
937 	}
938 
939 	device->nmatches++;
940 
941 	device->matches = g_realloc_n(device->matches, device->nmatches + 1, sizeof(WacomMatch*));
942 	device->matches[device->nmatches] = NULL;
943 	device->matches[device->nmatches - 1] = libwacom_match_ref(newmatch);
944 	device->match = device->nmatches - 1;
945 }
946 
947 LIBWACOM_EXPORT int
libwacom_get_vendor_id(const WacomDevice * device)948 libwacom_get_vendor_id(const WacomDevice *device)
949 {
950 	g_return_val_if_fail(device->match >= 0, -1);
951 	g_return_val_if_fail(device->match < device->nmatches, -1);
952 	return device->matches[device->match]->vendor_id;
953 }
954 
955 LIBWACOM_EXPORT const char*
libwacom_get_name(const WacomDevice * device)956 libwacom_get_name(const WacomDevice *device)
957 {
958 	return device->name;
959 }
960 
961 LIBWACOM_EXPORT const char*
libwacom_get_model_name(const WacomDevice * device)962 libwacom_get_model_name(const WacomDevice *device)
963 {
964 	return device->model_name;
965 }
966 
967 LIBWACOM_EXPORT const char*
libwacom_get_layout_filename(const WacomDevice * device)968 libwacom_get_layout_filename(const WacomDevice *device)
969 {
970 	return device->layout;
971 }
972 
973 LIBWACOM_EXPORT int
libwacom_get_product_id(const WacomDevice * device)974 libwacom_get_product_id(const WacomDevice *device)
975 {
976 	g_return_val_if_fail(device->match >= 0, -1);
977 	g_return_val_if_fail(device->match < device->nmatches, -1);
978 	return device->matches[device->match]->product_id;
979 }
980 
981 LIBWACOM_EXPORT const char*
libwacom_get_match(const WacomDevice * device)982 libwacom_get_match(const WacomDevice *device)
983 {
984 	g_return_val_if_fail(device->match >= 0, NULL);
985 	g_return_val_if_fail(device->match < device->nmatches, NULL);
986 	return device->matches[device->match]->match;
987 }
988 
989 LIBWACOM_EXPORT const WacomMatch**
libwacom_get_matches(const WacomDevice * device)990 libwacom_get_matches(const WacomDevice *device)
991 {
992 	return (const WacomMatch**)device->matches;
993 }
994 
995 LIBWACOM_EXPORT const WacomMatch*
libwacom_get_paired_device(const WacomDevice * device)996 libwacom_get_paired_device(const WacomDevice *device)
997 {
998 	return (const WacomMatch*)device->paired;
999 }
1000 
1001 LIBWACOM_EXPORT int
libwacom_get_width(const WacomDevice * device)1002 libwacom_get_width(const WacomDevice *device)
1003 {
1004 	return device->width;
1005 }
1006 
1007 LIBWACOM_EXPORT int
libwacom_get_height(const WacomDevice * device)1008 libwacom_get_height(const WacomDevice *device)
1009 {
1010 	return device->height;
1011 }
1012 
1013 LIBWACOM_EXPORT WacomClass
libwacom_get_class(const WacomDevice * device)1014 libwacom_get_class(const WacomDevice *device)
1015 {
1016 	return device->cls;
1017 }
1018 
1019 LIBWACOM_EXPORT int
libwacom_has_stylus(const WacomDevice * device)1020 libwacom_has_stylus(const WacomDevice *device)
1021 {
1022 	return !!(device->features & FEATURE_STYLUS);
1023 }
1024 
1025 LIBWACOM_EXPORT int
libwacom_has_touch(const WacomDevice * device)1026 libwacom_has_touch(const WacomDevice *device)
1027 {
1028 	return !!(device->features & FEATURE_TOUCH);
1029 }
1030 
1031 LIBWACOM_EXPORT int
libwacom_get_num_buttons(const WacomDevice * device)1032 libwacom_get_num_buttons(const WacomDevice *device)
1033 {
1034 	return device->num_buttons;
1035 }
1036 
1037 LIBWACOM_EXPORT const int *
libwacom_get_supported_styli(const WacomDevice * device,int * num_styli)1038 libwacom_get_supported_styli(const WacomDevice *device, int *num_styli)
1039 {
1040 	*num_styli = device->num_styli;
1041 	return device->supported_styli;
1042 }
1043 
1044 LIBWACOM_EXPORT int
libwacom_has_ring(const WacomDevice * device)1045 libwacom_has_ring(const WacomDevice *device)
1046 {
1047 	return !!(device->features & FEATURE_RING);
1048 }
1049 
1050 LIBWACOM_EXPORT int
libwacom_has_ring2(const WacomDevice * device)1051 libwacom_has_ring2(const WacomDevice *device)
1052 {
1053 	return !!(device->features & FEATURE_RING2);
1054 }
1055 
1056 LIBWACOM_EXPORT int
libwacom_get_ring_num_modes(const WacomDevice * device)1057 libwacom_get_ring_num_modes(const WacomDevice *device)
1058 {
1059 	return device->ring_num_modes;
1060 }
1061 
1062 LIBWACOM_EXPORT int
libwacom_get_ring2_num_modes(const WacomDevice * device)1063 libwacom_get_ring2_num_modes(const WacomDevice *device)
1064 {
1065 	return device->ring2_num_modes;
1066 }
1067 
1068 LIBWACOM_EXPORT int
libwacom_get_num_strips(const WacomDevice * device)1069 libwacom_get_num_strips(const WacomDevice *device)
1070 {
1071 	return device->num_strips;
1072 }
1073 
1074 LIBWACOM_EXPORT int
libwacom_get_strips_num_modes(const WacomDevice * device)1075 libwacom_get_strips_num_modes(const WacomDevice *device)
1076 {
1077 	return device->strips_num_modes;
1078 }
1079 
1080 LIBWACOM_EXPORT const WacomStatusLEDs *
libwacom_get_status_leds(const WacomDevice * device,int * num_leds)1081 libwacom_get_status_leds(const WacomDevice *device, int *num_leds)
1082 {
1083 	*num_leds = device->num_leds;
1084 	return device->status_leds;
1085 }
1086 
1087 struct {
1088 	WacomButtonFlags button_flags;
1089 	WacomStatusLEDs  status_leds;
1090 } button_status_leds[] = {
1091 	{ WACOM_BUTTON_RING_MODESWITCH,		WACOM_STATUS_LED_RING },
1092 	{ WACOM_BUTTON_RING2_MODESWITCH,	WACOM_STATUS_LED_RING2 },
1093 	{ WACOM_BUTTON_TOUCHSTRIP_MODESWITCH,	WACOM_STATUS_LED_TOUCHSTRIP },
1094 	{ WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH,	WACOM_STATUS_LED_TOUCHSTRIP2 }
1095 };
1096 
1097 LIBWACOM_EXPORT int
libwacom_get_button_led_group(const WacomDevice * device,char button)1098 libwacom_get_button_led_group (const WacomDevice *device, char button)
1099 {
1100 	int button_index, led_index;
1101 	WacomButtonFlags button_flags;
1102 
1103 	g_return_val_if_fail (device->num_buttons > 0, -1);
1104 	g_return_val_if_fail (button >= 'A', -1);
1105 	g_return_val_if_fail (button < 'A' + device->num_buttons, -1);
1106 
1107 	button_index = button - 'A';
1108 	button_flags = device->buttons[button_index];
1109 
1110 	if (!(button_flags & WACOM_BUTTON_MODESWITCH))
1111 		return -1;
1112 
1113 	for (led_index = 0; led_index < device->num_leds; led_index++) {
1114 		guint n;
1115 
1116 		for (n = 0; n < G_N_ELEMENTS (button_status_leds); n++) {
1117 			if ((button_flags & button_status_leds[n].button_flags) &&
1118 			    (device->status_leds[led_index] == button_status_leds[n].status_leds)) {
1119 				return led_index;
1120 			}
1121 		}
1122 	}
1123 
1124 	return WACOM_STATUS_LED_UNAVAILABLE;
1125 }
1126 
1127 LIBWACOM_EXPORT int
libwacom_is_builtin(const WacomDevice * device)1128 libwacom_is_builtin(const WacomDevice *device)
1129 {
1130 	return !!(libwacom_get_integration_flags (device) & WACOM_DEVICE_INTEGRATED_DISPLAY);
1131 }
1132 
1133 LIBWACOM_EXPORT int
libwacom_is_reversible(const WacomDevice * device)1134 libwacom_is_reversible(const WacomDevice *device)
1135 {
1136 	return !!(device->features & FEATURE_REVERSIBLE);
1137 }
1138 
1139 LIBWACOM_EXPORT int
libwacom_has_touchswitch(const WacomDevice * device)1140 libwacom_has_touchswitch(const WacomDevice *device)
1141 {
1142 	return !!(device->features & FEATURE_TOUCHSWITCH);
1143 }
1144 
1145 LIBWACOM_EXPORT WacomIntegrationFlags
libwacom_get_integration_flags(const WacomDevice * device)1146 libwacom_get_integration_flags (const WacomDevice *device)
1147 {
1148 	/* "unset" is for internal use only */
1149 	if (device->integration_flags == WACOM_DEVICE_INTEGRATED_UNSET)
1150 		return WACOM_DEVICE_INTEGRATED_NONE;
1151 
1152 	return device->integration_flags;
1153 }
1154 
1155 LIBWACOM_EXPORT WacomBusType
libwacom_get_bustype(const WacomDevice * device)1156 libwacom_get_bustype(const WacomDevice *device)
1157 {
1158 	g_return_val_if_fail(device->match >= 0, -1);
1159 	g_return_val_if_fail(device->match < device->nmatches, -1);
1160 	return device->matches[device->match]->bus;
1161 }
1162 
1163 LIBWACOM_EXPORT WacomButtonFlags
libwacom_get_button_flag(const WacomDevice * device,char button)1164 libwacom_get_button_flag(const WacomDevice *device, char button)
1165 {
1166 	int index;
1167 
1168 	g_return_val_if_fail (device->num_buttons > 0, WACOM_BUTTON_NONE);
1169 	g_return_val_if_fail (button >= 'A', WACOM_BUTTON_NONE);
1170 	g_return_val_if_fail (button < 'A' + device->num_buttons, WACOM_BUTTON_NONE);
1171 
1172 	index = button - 'A';
1173 
1174 	return device->buttons[index];
1175 }
1176 
1177 LIBWACOM_EXPORT int
libwacom_get_button_evdev_code(const WacomDevice * device,char button)1178 libwacom_get_button_evdev_code(const WacomDevice *device, char button)
1179 {
1180 	int index;
1181 
1182 	g_return_val_if_fail (device->num_buttons > 0, 0);
1183 	g_return_val_if_fail (button >= 'A', 0);
1184 	g_return_val_if_fail (button < 'A' + device->num_buttons, 0);
1185 
1186 	index = button - 'A';
1187 
1188 	return device->button_codes[index];
1189 }
1190 
1191 LIBWACOM_EXPORT const
libwacom_stylus_get_for_id(const WacomDeviceDatabase * db,int id)1192 WacomStylus *libwacom_stylus_get_for_id (const WacomDeviceDatabase *db, int id)
1193 {
1194 	return g_hash_table_lookup (db->stylus_ht, GINT_TO_POINTER(id));
1195 }
1196 
1197 LIBWACOM_EXPORT int
libwacom_stylus_get_id(const WacomStylus * stylus)1198 libwacom_stylus_get_id (const WacomStylus *stylus)
1199 {
1200 	return stylus->id;
1201 }
1202 
1203 LIBWACOM_EXPORT const char *
libwacom_stylus_get_name(const WacomStylus * stylus)1204 libwacom_stylus_get_name (const WacomStylus *stylus)
1205 {
1206 	return stylus->name;
1207 }
1208 
1209 LIBWACOM_EXPORT const int *
libwacom_stylus_get_paired_ids(const WacomStylus * stylus,int * num_paired_ids)1210 libwacom_stylus_get_paired_ids(const WacomStylus *stylus, int *num_paired_ids)
1211 {
1212 	if (num_paired_ids)
1213 		*num_paired_ids = stylus->num_ids;
1214 	return stylus->paired_ids;
1215 }
1216 
1217 LIBWACOM_EXPORT int
libwacom_stylus_get_num_buttons(const WacomStylus * stylus)1218 libwacom_stylus_get_num_buttons (const WacomStylus *stylus)
1219 {
1220 	if (stylus->num_buttons == -1) {
1221 		g_warning ("Stylus '0x%x' has no number of buttons defined, falling back to 2", stylus->id);
1222 		return 2;
1223 	}
1224 	return stylus->num_buttons;
1225 }
1226 
1227 LIBWACOM_EXPORT int
libwacom_stylus_has_eraser(const WacomStylus * stylus)1228 libwacom_stylus_has_eraser (const WacomStylus *stylus)
1229 {
1230 	return stylus->has_eraser;
1231 }
1232 
1233 LIBWACOM_EXPORT int
libwacom_stylus_is_eraser(const WacomStylus * stylus)1234 libwacom_stylus_is_eraser (const WacomStylus *stylus)
1235 {
1236 	return libwacom_stylus_get_eraser_type(stylus) != WACOM_ERASER_NONE;
1237 }
1238 
1239 LIBWACOM_EXPORT int
libwacom_stylus_has_lens(const WacomStylus * stylus)1240 libwacom_stylus_has_lens (const WacomStylus *stylus)
1241 {
1242 	return stylus->has_lens;
1243 }
1244 
1245 LIBWACOM_EXPORT int
libwacom_stylus_has_wheel(const WacomStylus * stylus)1246 libwacom_stylus_has_wheel (const WacomStylus *stylus)
1247 {
1248 	return stylus->has_wheel;
1249 }
1250 
1251 LIBWACOM_EXPORT WacomAxisTypeFlags
libwacom_stylus_get_axes(const WacomStylus * stylus)1252 libwacom_stylus_get_axes (const WacomStylus *stylus)
1253 {
1254 	return stylus->axes;
1255 }
1256 
1257 LIBWACOM_EXPORT WacomStylusType
libwacom_stylus_get_type(const WacomStylus * stylus)1258 libwacom_stylus_get_type (const WacomStylus *stylus)
1259 {
1260 	if (stylus->type == WSTYLUS_UNKNOWN) {
1261 		g_warning ("Stylus '0x%x' has no type defined, falling back to 'General'", stylus->id);
1262 		return WSTYLUS_GENERAL;
1263 	}
1264 	return stylus->type;
1265 }
1266 
1267 LIBWACOM_EXPORT WacomEraserType
libwacom_stylus_get_eraser_type(const WacomStylus * stylus)1268 libwacom_stylus_get_eraser_type (const WacomStylus *stylus)
1269 {
1270 	return stylus->eraser_type;
1271 }
1272 
1273 LIBWACOM_EXPORT void
libwacom_print_stylus_description(int fd,const WacomStylus * stylus)1274 libwacom_print_stylus_description (int fd, const WacomStylus *stylus)
1275 {
1276 	const char *type;
1277 	WacomAxisTypeFlags axes;
1278 	const int *paired_ids;
1279 	int count;
1280 	int i;
1281 
1282 	dprintf(fd, "[%#x]\n",		libwacom_stylus_get_id(stylus));
1283 	dprintf(fd, "Name=%s\n",	libwacom_stylus_get_name(stylus));
1284 	dprintf(fd, "Buttons=%d\n",	libwacom_stylus_get_num_buttons(stylus));
1285 	dprintf(fd, "PairedIds=");
1286 	paired_ids = libwacom_stylus_get_paired_ids(stylus, &count);
1287 	for (i = 0; i < count; i++) {
1288 		dprintf(fd, "%#x;", paired_ids[i]);
1289 	}
1290 	dprintf(fd, "\n");
1291 	switch (libwacom_stylus_get_eraser_type(stylus)) {
1292 		case WACOM_ERASER_UNKNOWN: type = "Unknown";       break;
1293 		case WACOM_ERASER_NONE:    type = "None";          break;
1294 		case WACOM_ERASER_INVERT:  type = "Invert";        break;
1295 		case WACOM_ERASER_BUTTON:  type = "Button";        break;
1296 		default:                   g_assert_not_reached(); break;
1297 	}
1298 	dprintf(fd, "EraserType=%s\n", type);
1299 	dprintf(fd, "HasLens=%s\n",	libwacom_stylus_has_lens(stylus) ? "true" : "false");
1300 	dprintf(fd, "HasWheel=%s\n",	libwacom_stylus_has_wheel(stylus) ? "true" : "false");
1301 	axes = libwacom_stylus_get_axes(stylus);
1302 	dprintf(fd, "Axes=");
1303 	if (axes & WACOM_AXIS_TYPE_TILT)
1304 		dprintf(fd, "Tilt;");
1305 	if (axes & WACOM_AXIS_TYPE_ROTATION_Z)
1306 		dprintf(fd, "RotationZ;");
1307 	if (axes & WACOM_AXIS_TYPE_DISTANCE)
1308 		dprintf(fd, "Distance;");
1309 	if (axes & WACOM_AXIS_TYPE_PRESSURE)
1310 		dprintf(fd, "Pressure;");
1311 	if (axes & WACOM_AXIS_TYPE_SLIDER)
1312 		dprintf(fd, "Slider;");
1313 	dprintf(fd, "\n");
1314 
1315 	switch(libwacom_stylus_get_type(stylus)) {
1316 		case WSTYLUS_UNKNOWN:	type = "Unknown";	 break;
1317 		case WSTYLUS_GENERAL:	type = "General";	 break;
1318 		case WSTYLUS_INKING:	type = "Inking";	 break;
1319 		case WSTYLUS_AIRBRUSH:	type = "Airbrush";	 break;
1320 		case WSTYLUS_CLASSIC:	type = "Classic";	 break;
1321 		case WSTYLUS_MARKER:	type = "Marker";	 break;
1322 		case WSTYLUS_STROKE:	type = "Stroke";	 break;
1323 		case WSTYLUS_PUCK:	type = "Puck";		break;
1324 		case WSTYLUS_3D:	type = "3D";		break;
1325 		case WSTYLUS_MOBILE:	type = "Mobile";	break;
1326 		default:		g_assert_not_reached();	break;
1327 	}
1328 
1329 	dprintf(fd, "Type=%s\n", type);
1330 }
1331 
1332 WacomStylus*
libwacom_stylus_ref(WacomStylus * stylus)1333 libwacom_stylus_ref(WacomStylus *stylus)
1334 {
1335 	g_atomic_int_inc(&stylus->refcnt);
1336 
1337 	return stylus;
1338 }
1339 
1340 WacomStylus*
libwacom_stylus_unref(WacomStylus * stylus)1341 libwacom_stylus_unref(WacomStylus *stylus)
1342 {
1343 	if (!g_atomic_int_dec_and_test(&stylus->refcnt))
1344 		return NULL;
1345 
1346 	g_free (stylus->name);
1347 	g_free (stylus->group);
1348 	g_free (stylus->paired_ids);
1349 	g_free (stylus);
1350 
1351 	return NULL;
1352 }
1353 
1354 LIBWACOM_EXPORT const char *
libwacom_match_get_name(const WacomMatch * match)1355 libwacom_match_get_name(const WacomMatch *match)
1356 {
1357 	return match->name;
1358 }
1359 
1360 LIBWACOM_EXPORT WacomBusType
libwacom_match_get_bustype(const WacomMatch * match)1361 libwacom_match_get_bustype(const WacomMatch *match)
1362 {
1363 	return match->bus;
1364 }
1365 
1366 LIBWACOM_EXPORT uint32_t
libwacom_match_get_product_id(const WacomMatch * match)1367 libwacom_match_get_product_id(const WacomMatch *match)
1368 {
1369 	return match->product_id;
1370 }
1371 
1372 LIBWACOM_EXPORT uint32_t
libwacom_match_get_vendor_id(const WacomMatch * match)1373 libwacom_match_get_vendor_id(const WacomMatch *match)
1374 {
1375 	return match->vendor_id;
1376 }
1377 
1378 LIBWACOM_EXPORT const char*
libwacom_match_get_match_string(const WacomMatch * match)1379 libwacom_match_get_match_string(const WacomMatch *match)
1380 {
1381 	return match->match;
1382 }
1383 
1384 /* vim: set noexpandtab tabstop=8 shiftwidth=8: */
1385