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