2
* Copyright © 2011 Red Hat, Inc.
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
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.
24
* Peter Hutterer (peter.hutterer@redhat.com)
31
#include "libwacomint.h"
35
#include <gudev/gudev.h>
37
static const WacomDevice *
38
libwacom_get_device(WacomDeviceDatabase *db, const char *match)
40
return (WacomDevice *) g_hash_table_lookup (db->device_ht, match);
44
get_device_info (const char *path,
54
const char * const subsystems[] = { "input", NULL };
60
*builtin = IS_BUILTIN_UNSET;
62
client = g_udev_client_new (subsystems);
63
device = g_udev_client_query_by_device_file (client, path);
65
libwacom_error_set(error, WERROR_INVALID_PATH, "Could not find device '%s' in udev", path);
69
if (g_udev_device_get_property_as_boolean (device, "ID_INPUT_TABLET") == FALSE) {
70
libwacom_error_set(error, WERROR_INVALID_PATH, "Device '%s' is not a tablet", path);
74
bus_str = g_udev_device_get_property (device, "ID_BUS");
75
/* Serial devices are weird */
76
if (bus_str == NULL) {
77
if (g_strcmp0 (g_udev_device_get_subsystem (device), "tty") == 0)
80
/* Poke the parent device for Bluetooth models */
81
if (bus_str == NULL) {
84
parent = g_udev_device_get_parent (device);
86
g_object_unref (device);
88
bus_str = "bluetooth";
91
/* Is the device builtin? */
92
devname = g_udev_device_get_name (device);
93
if (devname != NULL) {
94
char *sysfs_path, *contents;
96
sysfs_path = g_build_filename ("/sys/class/input", devname, "device/properties", NULL);
97
if (g_file_get_contents (sysfs_path, &contents, NULL, NULL)) {
100
* 0x02: DIRECT flag */
101
flag = atoi(contents);
102
*builtin = (flag & 0x02) == 0x02 ? IS_BUILTIN_TRUE : IS_BUILTIN_FALSE;
108
*name = g_strdup (g_udev_device_get_sysfs_attr (device, "name"));
109
/* Try getting the name from the parent if that fails */
113
parent = g_udev_device_get_parent (device);
114
*name = g_strdup (g_udev_device_get_sysfs_attr (parent, "name"));
115
g_object_unref (parent);
118
*bus = bus_from_str (bus_str);
119
if (*bus == WBUSTYPE_USB) {
120
const char *vendor_str, *product_str;
122
vendor_str = g_udev_device_get_property (device, "ID_VENDOR_ID");
123
product_str = g_udev_device_get_property (device, "ID_MODEL_ID");
125
*vendor_id = strtol (vendor_str, NULL, 16);
126
*product_id = strtol (product_str, NULL, 16);
127
} else if (*bus == WBUSTYPE_BLUETOOTH) {
128
const char *product_str;
132
* E: PRODUCT=5/56a/81/100
136
product_str = g_udev_device_get_property (device, "PRODUCT");
137
g_assert (product_str);
138
if (sscanf(product_str, "%d/%x/%x/%d", &garbage, vendor_id, product_id, &garbage) != 4) {
139
libwacom_error_set(error, WERROR_UNKNOWN_MODEL, "Unimplemented serial bus");
142
} else if (*bus == WBUSTYPE_SERIAL) {
143
/* FIXME This matches the declaration in serial-wacf004.tablet
144
* Might not be good enough though */
148
libwacom_error_set(error, WERROR_UNKNOWN_MODEL, "Unsupported bus '%s'", bus_str);
152
if (*bus != WBUSTYPE_UNKNOWN &&
156
/* The serial bus uses 0:0 as the vid/pid */
157
if (*bus == WBUSTYPE_SERIAL)
164
g_object_unref (device);
166
g_object_unref (client);
171
libwacom_copy(const WacomDevice *device)
175
d = g_new0 (WacomDevice, 1);
176
d->name = g_strdup (device->name);
177
d->width = device->width;
178
d->height = device->height;
179
d->match = g_strdup (device->match);
180
d->vendor_id = device->vendor_id;
181
d->product_id = device->product_id;
182
d->cls = device->cls;
183
d->bus = device->bus;
184
d->num_strips = device->num_strips;
185
d->features = device->features;
186
d->strips_num_modes = device->strips_num_modes;
187
d->ring_num_modes = device->ring_num_modes;
188
d->ring2_num_modes = device->ring2_num_modes;
189
d->num_styli = device->num_styli;
190
d->supported_styli = g_memdup (device->supported_styli, sizeof(int) * device->num_styli);
191
d->num_buttons = device->num_buttons;
192
d->buttons = g_memdup (device->buttons, sizeof(WacomButtonFlags) * device->num_buttons);
196
static const WacomDevice *
197
libwacom_new (WacomDeviceDatabase *db, int vendor_id, int product_id, WacomBusType bus, WacomError *error)
199
const WacomDevice *device;
203
libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
207
match = g_strdup_printf ("%s:%04x:%04x", bus_to_str (bus), vendor_id, product_id);
208
device = libwacom_get_device(db, match);
215
libwacom_new_from_path(WacomDeviceDatabase *db, const char *path, int fallback, WacomError *error)
217
int vendor_id, product_id;
219
const WacomDevice *device;
225
libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
230
libwacom_error_set(error, WERROR_INVALID_PATH, "path is NULL");
234
if (!get_device_info (path, &vendor_id, &product_id, &name, &bus, &builtin, error))
237
device = libwacom_new (db, vendor_id, product_id, bus, error);
239
ret = libwacom_copy(device);
243
if (device == NULL && fallback) {
244
device = libwacom_get_device(db, "generic");
248
ret = libwacom_copy(device);
254
ret->vendor_id = vendor_id;
255
ret->product_id = product_id;
258
ret->match = g_strdup_printf ("%s:0x%x:0x%x", bus_to_str (bus), vendor_id, product_id);
264
if (builtin == IS_BUILTIN_TRUE)
265
ret->features |= FEATURE_BUILTIN;
266
else if (builtin == IS_BUILTIN_FALSE)
267
ret->features &= ~FEATURE_BUILTIN;
274
libwacom_error_set(error, WERROR_UNKNOWN_MODEL, NULL);
279
libwacom_new_from_usbid(WacomDeviceDatabase *db, int vendor_id, int product_id, WacomError *error)
281
const WacomDevice *device;
284
libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
288
device = libwacom_new(db, vendor_id, product_id, WBUSTYPE_USB, error);
291
return libwacom_copy(device);
293
libwacom_error_set(error, WERROR_UNKNOWN_MODEL, NULL);
298
libwacom_new_from_name(WacomDeviceDatabase *db, const char *name, WacomError *error)
300
const WacomDevice *device;
304
libwacom_error_set(error, WERROR_INVALID_DB, "db is NULL");
309
keys = g_hash_table_get_values (db->device_ht);
310
for (l = keys; l; l = l->next) {
311
WacomDevice *d = l->data;
313
if (g_strcmp0 (d->name, name) == 0) {
321
return libwacom_copy(device);
323
libwacom_error_set(error, WERROR_UNKNOWN_MODEL, NULL);
328
libwacom_destroy(WacomDevice *device)
330
g_free (device->name);
332
g_free (device->match);
333
g_free (device->supported_styli);
334
g_free (device->buttons);
338
int libwacom_get_vendor_id(WacomDevice *device)
340
return device->vendor_id;
343
const char* libwacom_get_name(WacomDevice *device)
348
int libwacom_get_product_id(WacomDevice *device)
350
return device->product_id;
353
const char* libwacom_get_match(WacomDevice *device)
355
/* FIXME make sure this only returns the first match
356
* when we implement multiple matching */
357
return device->match;
360
int libwacom_get_width(WacomDevice *device)
362
return device->width;
365
int libwacom_get_height(WacomDevice *device)
367
return device->height;
371
libwacom_get_class(WacomDevice *device)
376
int libwacom_has_stylus(WacomDevice *device)
378
return !!(device->features & FEATURE_STYLUS);
381
int libwacom_has_touch(WacomDevice *device)
383
return !!(device->features & FEATURE_TOUCH);
386
int libwacom_get_num_buttons(WacomDevice *device)
388
return device->num_buttons;
391
int *libwacom_get_supported_styli(WacomDevice *device, int *num_styli)
393
*num_styli = device->num_styli;
394
return device->supported_styli;
397
int libwacom_has_ring(WacomDevice *device)
399
return !!(device->features & FEATURE_RING);
402
int libwacom_has_ring2(WacomDevice *device)
404
return !!(device->features & FEATURE_RING2);
407
int libwacom_get_ring_num_modes(WacomDevice *device)
409
return device->ring_num_modes;
412
int libwacom_get_ring2_num_modes(WacomDevice *device)
414
return device->ring2_num_modes;
417
int libwacom_get_num_strips(WacomDevice *device)
419
return device->num_strips;
422
int libwacom_get_strips_num_modes(WacomDevice *device)
424
return device->strips_num_modes;
427
int libwacom_is_builtin(WacomDevice *device)
429
return !!(device->features & FEATURE_BUILTIN);
432
int libwacom_is_reversible(WacomDevice *device)
434
return !!(device->features & FEATURE_REVERSIBLE);
437
WacomBusType libwacom_get_bustype(WacomDevice *device)
443
libwacom_get_button_flag(WacomDevice *device,
448
g_return_val_if_fail (device->num_buttons > 0, WACOM_BUTTON_NONE);
449
g_return_val_if_fail (button >= 'A', WACOM_BUTTON_NONE);
450
g_return_val_if_fail (button < 'A' + device->num_buttons, WACOM_BUTTON_NONE);
452
index = button - 'A';
454
return device->buttons[index];
457
const WacomStylus *libwacom_stylus_get_for_id (WacomDeviceDatabase *db, int id)
459
return g_hash_table_lookup (db->stylus_ht, GINT_TO_POINTER(id));
462
int libwacom_stylus_get_id (const WacomStylus *stylus)
467
const char *libwacom_stylus_get_name (const WacomStylus *stylus)
472
int libwacom_stylus_get_num_buttons (const WacomStylus *stylus)
474
if (stylus->num_buttons == -1) {
475
g_warning ("Stylus '0x%x' has no number of buttons defined, falling back to 2", stylus->id);
478
return stylus->num_buttons;
481
int libwacom_stylus_has_eraser (const WacomStylus *stylus)
483
return stylus->has_eraser;
486
int libwacom_stylus_is_eraser (const WacomStylus *stylus)
488
return stylus->is_eraser;
491
int libwacom_stylus_has_lens (const WacomStylus *stylus)
493
return stylus->has_lens;
496
WacomStylusType libwacom_stylus_get_type (const WacomStylus *stylus)
498
if (stylus->type == WSTYLUS_UNKNOWN) {
499
g_warning ("Stylus '0x%x' has no type defined, falling back to 'General'", stylus->id);
500
return WSTYLUS_GENERAL;
505
void libwacom_stylus_destroy(WacomStylus *stylus)
507
g_free (stylus->name);
511
/* vim :noexpandtab shiftwidth=8: */