1/* 2 * Copyright © 2016 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "config.h" 25#include "evdev-tablet-pad.h" 26#include "util-input-event.h" 27 28#include <assert.h> 29#include <stdbool.h> 30#include <string.h> 31 32#if HAVE_LIBWACOM 33#include <libwacom/libwacom.h> 34#endif 35 36#define pad_set_status(pad_,s_) (pad_)->status |= (s_) 37#define pad_unset_status(pad_,s_) (pad_)->status &= ~(s_) 38#define pad_has_status(pad_,s_) (!!((pad_)->status & (s_))) 39 40static void 41pad_get_buttons_pressed(struct pad_dispatch *pad, 42 struct button_state *buttons) 43{ 44 struct button_state *state = &pad->button_state; 45 struct button_state *prev_state = &pad->prev_button_state; 46 unsigned int i; 47 48 for (i = 0; i < sizeof(buttons->bits); i++) 49 buttons->bits[i] = state->bits[i] & ~(prev_state->bits[i]); 50} 51 52static void 53pad_get_buttons_released(struct pad_dispatch *pad, 54 struct button_state *buttons) 55{ 56 struct button_state *state = &pad->button_state; 57 struct button_state *prev_state = &pad->prev_button_state; 58 unsigned int i; 59 60 for (i = 0; i < sizeof(buttons->bits); i++) 61 buttons->bits[i] = prev_state->bits[i] & ~(state->bits[i]); 62} 63 64static inline bool 65pad_button_is_down(const struct pad_dispatch *pad, 66 uint32_t button) 67{ 68 return bit_is_set(pad->button_state.bits, button); 69} 70 71static inline bool 72pad_any_button_down(const struct pad_dispatch *pad) 73{ 74 const struct button_state *state = &pad->button_state; 75 unsigned int i; 76 77 for (i = 0; i < sizeof(state->bits); i++) 78 if (state->bits[i] != 0) 79 return true; 80 81 return false; 82} 83 84static inline void 85pad_button_set_down(struct pad_dispatch *pad, 86 uint32_t button, 87 bool is_down) 88{ 89 struct button_state *state = &pad->button_state; 90 91 if (is_down) { 92 set_bit(state->bits, button); 93 pad_set_status(pad, PAD_BUTTONS_PRESSED); 94 } else { 95 clear_bit(state->bits, button); 96 pad_set_status(pad, PAD_BUTTONS_RELEASED); 97 } 98} 99 100static void 101pad_process_absolute(struct pad_dispatch *pad, 102 struct evdev_device *device, 103 struct input_event *e, 104 uint64_t time) 105{ 106 switch (e->code) { 107 case ABS_WHEEL: 108 pad->changed_axes |= PAD_AXIS_RING1; 109 pad_set_status(pad, PAD_AXES_UPDATED); 110 break; 111 case ABS_THROTTLE: 112 pad->changed_axes |= PAD_AXIS_RING2; 113 pad_set_status(pad, PAD_AXES_UPDATED); 114 break; 115 case ABS_RX: 116 pad->changed_axes |= PAD_AXIS_STRIP1; 117 pad_set_status(pad, PAD_AXES_UPDATED); 118 break; 119 case ABS_RY: 120 pad->changed_axes |= PAD_AXIS_STRIP2; 121 pad_set_status(pad, PAD_AXES_UPDATED); 122 break; 123 case ABS_MISC: 124 /* The wacom driver always sends a 0 axis event on finger 125 up, but we also get an ABS_MISC 15 on touch down and 126 ABS_MISC 0 on touch up, on top of the actual event. This 127 is kernel behavior for xf86-input-wacom backwards 128 compatibility after the 3.17 wacom HID move. 129 130 We use that event to tell when we truly went a full 131 rotation around the wheel vs. a finger release. 132 133 FIXME: On the Intuos5 and later the kernel merges all 134 states into that event, so if any finger is down on any 135 button, the wheel release won't trigger the ABS_MISC 0 136 but still send a 0 event. We can't currently detect this. 137 */ 138 pad->have_abs_misc_terminator = true; 139 break; 140 default: 141 evdev_log_info(device, 142 "Unhandled EV_ABS event code %#x\n", 143 e->code); 144 break; 145 } 146} 147 148static inline double 149normalize_ring(const struct input_absinfo *absinfo) 150{ 151 /* libinput has 0 as the ring's northernmost point in the device's 152 current logical rotation, increasing clockwise to 1. Wacom has 153 0 on the left-most wheel position. 154 */ 155 double range = absinfo_range(absinfo); 156 double value = (absinfo->value - absinfo->minimum) / range - 0.25; 157 158 if (value < 0.0) 159 value += 1.0; 160 161 return value; 162} 163 164static inline double 165normalize_strip(const struct input_absinfo *absinfo) 166{ 167 /* strip axes don't use a proper value, they just shift the bit left 168 * for each position. 0 isn't a real value either, it's only sent on 169 * finger release */ 170 double min = 0, 171 max = log2(absinfo->maximum); 172 double range = max - min; 173 double value = (log2(absinfo->value) - min) / range; 174 175 return value; 176} 177 178static inline double 179pad_handle_ring(struct pad_dispatch *pad, 180 struct evdev_device *device, 181 unsigned int code) 182{ 183 const struct input_absinfo *absinfo; 184 double degrees; 185 186 absinfo = libevdev_get_abs_info(device->evdev, code); 187 assert(absinfo); 188 189 degrees = normalize_ring(absinfo) * 360; 190 191 if (device->left_handed.enabled) 192 degrees = fmod(degrees + 180, 360); 193 194 return degrees; 195} 196 197static inline double 198pad_handle_strip(struct pad_dispatch *pad, 199 struct evdev_device *device, 200 unsigned int code) 201{ 202 const struct input_absinfo *absinfo; 203 double pos; 204 205 absinfo = libevdev_get_abs_info(device->evdev, code); 206 assert(absinfo); 207 208 if (absinfo->value == 0) 209 return 0.0; 210 211 pos = normalize_strip(absinfo); 212 213 if (device->left_handed.enabled) 214 pos = 1.0 - pos; 215 216 return pos; 217} 218 219static inline struct libinput_tablet_pad_mode_group * 220pad_ring_get_mode_group(struct pad_dispatch *pad, 221 unsigned int ring) 222{ 223 struct libinput_tablet_pad_mode_group *group; 224 225 list_for_each(group, &pad->modes.mode_group_list, link) { 226 if (libinput_tablet_pad_mode_group_has_ring(group, ring)) 227 return group; 228 } 229 230 assert(!"Unable to find ring mode group"); 231 232 return NULL; 233} 234 235static inline struct libinput_tablet_pad_mode_group * 236pad_strip_get_mode_group(struct pad_dispatch *pad, 237 unsigned int strip) 238{ 239 struct libinput_tablet_pad_mode_group *group; 240 241 list_for_each(group, &pad->modes.mode_group_list, link) { 242 if (libinput_tablet_pad_mode_group_has_strip(group, strip)) 243 return group; 244 } 245 246 assert(!"Unable to find strip mode group"); 247 248 return NULL; 249} 250 251static void 252pad_check_notify_axes(struct pad_dispatch *pad, 253 struct evdev_device *device, 254 uint64_t time) 255{ 256 struct libinput_device *base = &device->base; 257 struct libinput_tablet_pad_mode_group *group; 258 double value; 259 bool send_finger_up = false; 260 261 /* Suppress the reset to 0 on finger up. See the 262 comment in pad_process_absolute */ 263 if (pad->have_abs_misc_terminator && 264 libevdev_get_event_value(device->evdev, EV_ABS, ABS_MISC) == 0) 265 send_finger_up = true; 266 267 if (pad->changed_axes & PAD_AXIS_RING1) { 268 value = pad_handle_ring(pad, device, ABS_WHEEL); 269 if (send_finger_up) 270 value = -1.0; 271 272 group = pad_ring_get_mode_group(pad, 0); 273 tablet_pad_notify_ring(base, 274 time, 275 0, 276 value, 277 LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER, 278 group); 279 } 280 281 if (pad->changed_axes & PAD_AXIS_RING2) { 282 value = pad_handle_ring(pad, device, ABS_THROTTLE); 283 if (send_finger_up) 284 value = -1.0; 285 286 group = pad_ring_get_mode_group(pad, 1); 287 tablet_pad_notify_ring(base, 288 time, 289 1, 290 value, 291 LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER, 292 group); 293 } 294 295 if (pad->changed_axes & PAD_AXIS_STRIP1) { 296 value = pad_handle_strip(pad, device, ABS_RX); 297 if (send_finger_up) 298 value = -1.0; 299 300 group = pad_strip_get_mode_group(pad, 0); 301 tablet_pad_notify_strip(base, 302 time, 303 0, 304 value, 305 LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER, 306 group); 307 } 308 309 if (pad->changed_axes & PAD_AXIS_STRIP2) { 310 value = pad_handle_strip(pad, device, ABS_RY); 311 if (send_finger_up) 312 value = -1.0; 313 314 group = pad_strip_get_mode_group(pad, 1); 315 tablet_pad_notify_strip(base, 316 time, 317 1, 318 value, 319 LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER, 320 group); 321 } 322 323 pad->changed_axes = PAD_AXIS_NONE; 324 pad->have_abs_misc_terminator = false; 325} 326 327static void 328pad_process_key(struct pad_dispatch *pad, 329 struct evdev_device *device, 330 struct input_event *e, 331 uint64_t time) 332{ 333 uint32_t button = e->code; 334 uint32_t is_press = e->value != 0; 335 336 /* ignore kernel key repeat */ 337 if (e->value == 2) 338 return; 339 340 pad_button_set_down(pad, button, is_press); 341} 342 343static inline struct libinput_tablet_pad_mode_group * 344pad_button_get_mode_group(struct pad_dispatch *pad, 345 unsigned int button) 346{ 347 struct libinput_tablet_pad_mode_group *group; 348 349 list_for_each(group, &pad->modes.mode_group_list, link) { 350 if (libinput_tablet_pad_mode_group_has_button(group, button)) 351 return group; 352 } 353 354 assert(!"Unable to find button mode group\n"); 355 356 return NULL; 357} 358 359static void 360pad_notify_button_mask(struct pad_dispatch *pad, 361 struct evdev_device *device, 362 uint64_t time, 363 const struct button_state *buttons, 364 enum libinput_button_state state) 365{ 366 struct libinput_device *base = &device->base; 367 struct libinput_tablet_pad_mode_group *group; 368 int32_t code; 369 unsigned int i; 370 371 for (i = 0; i < sizeof(buttons->bits); i++) { 372 unsigned char buttons_slice = buttons->bits[i]; 373 374 code = i * 8; 375 while (buttons_slice) { 376 int enabled; 377 key_or_button_map_t map; 378 379 code++; 380 enabled = (buttons_slice & 1); 381 buttons_slice >>= 1; 382 383 if (!enabled) 384 continue; 385 386 map = pad->button_map[code - 1]; 387 if (map_is_unmapped(map)) 388 continue; 389 390 if (map_is_button(map)) { 391 int32_t button = map_value(map); 392 393 group = pad_button_get_mode_group(pad, button); 394 pad_button_update_mode(group, button, state); 395 tablet_pad_notify_button(base, 396 time, 397 button, 398 state, 399 group); 400 } else if (map_is_key(map)) { 401 uint32_t key = map_value(map); 402 403 tablet_pad_notify_key(base, 404 time, 405 key, 406 (enum libinput_key_state)state); 407 } else { 408 abort(); 409 } 410 } 411 } 412} 413 414static void 415pad_notify_buttons(struct pad_dispatch *pad, 416 struct evdev_device *device, 417 uint64_t time, 418 enum libinput_button_state state) 419{ 420 struct button_state buttons; 421 422 if (state == LIBINPUT_BUTTON_STATE_PRESSED) 423 pad_get_buttons_pressed(pad, &buttons); 424 else 425 pad_get_buttons_released(pad, &buttons); 426 427 pad_notify_button_mask(pad, device, time, &buttons, state); 428} 429 430static void 431pad_change_to_left_handed(struct evdev_device *device) 432{ 433 struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch; 434 435 if (device->left_handed.enabled == device->left_handed.want_enabled) 436 return; 437 438 if (pad_any_button_down(pad)) 439 return; 440 441 device->left_handed.enabled = device->left_handed.want_enabled; 442} 443 444static void 445pad_flush(struct pad_dispatch *pad, 446 struct evdev_device *device, 447 uint64_t time) 448{ 449 if (pad_has_status(pad, PAD_AXES_UPDATED)) { 450 pad_check_notify_axes(pad, device, time); 451 pad_unset_status(pad, PAD_AXES_UPDATED); 452 } 453 454 if (pad_has_status(pad, PAD_BUTTONS_RELEASED)) { 455 pad_notify_buttons(pad, 456 device, 457 time, 458 LIBINPUT_BUTTON_STATE_RELEASED); 459 pad_unset_status(pad, PAD_BUTTONS_RELEASED); 460 461 pad_change_to_left_handed(device); 462 } 463 464 if (pad_has_status(pad, PAD_BUTTONS_PRESSED)) { 465 pad_notify_buttons(pad, 466 device, 467 time, 468 LIBINPUT_BUTTON_STATE_PRESSED); 469 pad_unset_status(pad, PAD_BUTTONS_PRESSED); 470 } 471 472 /* Update state */ 473 memcpy(&pad->prev_button_state, 474 &pad->button_state, 475 sizeof(pad->button_state)); 476} 477 478static void 479pad_process(struct evdev_dispatch *dispatch, 480 struct evdev_device *device, 481 struct input_event *e, 482 uint64_t time) 483{ 484 struct pad_dispatch *pad = pad_dispatch(dispatch); 485 486 switch (e->type) { 487 case EV_ABS: 488 pad_process_absolute(pad, device, e, time); 489 break; 490 case EV_KEY: 491 pad_process_key(pad, device, e, time); 492 break; 493 case EV_SYN: 494 pad_flush(pad, device, time); 495 break; 496 case EV_MSC: 497 /* The EKR sends the serial as MSC_SERIAL, ignore this for 498 * now */ 499 break; 500 default: 501 evdev_log_error(device, 502 "Unexpected event type %s (%#x)\n", 503 libevdev_event_type_get_name(e->type), 504 e->type); 505 break; 506 } 507} 508 509static void 510pad_suspend(struct evdev_dispatch *dispatch, 511 struct evdev_device *device) 512{ 513 struct pad_dispatch *pad = pad_dispatch(dispatch); 514 struct libinput *libinput = pad_libinput_context(pad); 515 unsigned int code; 516 517 for (code = KEY_ESC; code < KEY_CNT; code++) { 518 if (pad_button_is_down(pad, code)) 519 pad_button_set_down(pad, code, false); 520 } 521 522 pad_flush(pad, device, libinput_now(libinput)); 523} 524 525static void 526pad_destroy(struct evdev_dispatch *dispatch) 527{ 528 struct pad_dispatch *pad = pad_dispatch(dispatch); 529 530 pad_destroy_leds(pad); 531 free(pad); 532} 533 534static struct evdev_dispatch_interface pad_interface = { 535 .process = pad_process, 536 .suspend = pad_suspend, 537 .remove = NULL, 538 .destroy = pad_destroy, 539 .device_added = NULL, 540 .device_removed = NULL, 541 .device_suspended = NULL, 542 .device_resumed = NULL, 543 .post_added = NULL, 544 .touch_arbitration_toggle = NULL, 545 .touch_arbitration_update_rect = NULL, 546 .get_switch_state = NULL, 547}; 548 549static bool 550pad_init_buttons_from_libwacom(struct pad_dispatch *pad, 551 struct evdev_device *device) 552{ 553 bool rc = false; 554#if HAVE_LIBWACOM 555 struct libinput *li = pad_libinput_context(pad); 556 WacomDeviceDatabase *db = NULL; 557 WacomDevice *tablet = NULL; 558 int num_buttons; 559 int map = 0; 560 char event_path[64]; 561 562 db = libinput_libwacom_ref(li); 563 if (!db) 564 goto out; 565 566 snprintf(event_path, 567 sizeof(event_path), 568 "/dev/input/%s", 569 evdev_device_get_sysname(device)); 570 tablet = libwacom_new_from_path(db, 571 event_path, 572 WFALLBACK_NONE, 573 NULL); 574 if (!tablet) { 575 tablet = libwacom_new_from_usbid(db, 576 evdev_device_get_id_vendor(device), 577 evdev_device_get_id_product(device), 578 NULL); 579 } 580 581 if (!tablet) 582 goto out; 583 584 num_buttons = libwacom_get_num_buttons(tablet); 585 for (int i = 0; i < num_buttons; i++) { 586 unsigned int code; 587 588 code = libwacom_get_button_evdev_code(tablet, 'A' + i); 589 if (code == 0) 590 continue; 591 592 map_set_button_map(pad->button_map[code], map++); 593 } 594 595 pad->nbuttons = map; 596 597 rc = true; 598out: 599 if (tablet) 600 libwacom_destroy(tablet); 601 if (db) 602 libinput_libwacom_unref(li); 603#endif 604 return rc; 605} 606 607static void 608pad_init_buttons_from_kernel(struct pad_dispatch *pad, 609 struct evdev_device *device) 610{ 611 unsigned int code; 612 int map = 0; 613 614 /* we match wacom_report_numbered_buttons() from the kernel */ 615 for (code = BTN_0; code < BTN_0 + 10; code++) { 616 if (libevdev_has_event_code(device->evdev, EV_KEY, code)) 617 map_set_button_map(pad->button_map[code], map++); 618 } 619 620 for (code = BTN_BASE; code < BTN_BASE + 2; code++) { 621 if (libevdev_has_event_code(device->evdev, EV_KEY, code)) 622 map_set_button_map(pad->button_map[code], map++); 623 } 624 625 for (code = BTN_A; code < BTN_A + 6; code++) { 626 if (libevdev_has_event_code(device->evdev, EV_KEY, code)) 627 map_set_button_map(pad->button_map[code], map++); 628 } 629 630 for (code = BTN_LEFT; code < BTN_LEFT + 7; code++) { 631 if (libevdev_has_event_code(device->evdev, EV_KEY, code)) 632 map_set_button_map(pad->button_map[code], map++); 633 } 634 635 pad->nbuttons = map; 636} 637 638static void 639pad_init_keys(struct pad_dispatch *pad, struct evdev_device *device) 640{ 641 unsigned int codes[] = { 642 KEY_BUTTONCONFIG, 643 KEY_ONSCREEN_KEYBOARD, 644 KEY_CONTROLPANEL, 645 }; 646 647 /* Wacom's keys are the only ones we know anything about */ 648 if (libevdev_get_id_vendor(device->evdev) != VENDOR_ID_WACOM) 649 return; 650 651 ARRAY_FOR_EACH(codes, code) { 652 if (libevdev_has_event_code(device->evdev, EV_KEY, *code)) 653 map_set_key_map(pad->button_map[*code], *code); 654 } 655} 656 657static void 658pad_init_buttons(struct pad_dispatch *pad, 659 struct evdev_device *device) 660{ 661 size_t i; 662 663 for (i = 0; i < ARRAY_LENGTH(pad->button_map); i++) 664 map_init(pad->button_map[i]); 665 666 if (!pad_init_buttons_from_libwacom(pad, device)) 667 pad_init_buttons_from_kernel(pad, device); 668 669 pad_init_keys(pad, device); 670} 671 672static void 673pad_init_left_handed(struct evdev_device *device) 674{ 675 if (evdev_tablet_has_left_handed(device)) 676 evdev_init_left_handed(device, 677 pad_change_to_left_handed); 678} 679 680static int 681pad_init(struct pad_dispatch *pad, struct evdev_device *device) 682{ 683 pad->base.dispatch_type = DISPATCH_TABLET_PAD; 684 pad->base.interface = &pad_interface; 685 pad->device = device; 686 pad->status = PAD_NONE; 687 pad->changed_axes = PAD_AXIS_NONE; 688 689 pad_init_buttons(pad, device); 690 pad_init_left_handed(device); 691 if (pad_init_leds(pad, device) != 0) 692 return 1; 693 694 return 0; 695} 696 697static uint32_t 698pad_sendevents_get_modes(struct libinput_device *device) 699{ 700 return LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; 701} 702 703static enum libinput_config_status 704pad_sendevents_set_mode(struct libinput_device *device, 705 enum libinput_config_send_events_mode mode) 706{ 707 struct evdev_device *evdev = evdev_device(device); 708 struct pad_dispatch *pad = (struct pad_dispatch*)evdev->dispatch; 709 710 if (mode == pad->sendevents.current_mode) 711 return LIBINPUT_CONFIG_STATUS_SUCCESS; 712 713 switch(mode) { 714 case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED: 715 break; 716 case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED: 717 pad_suspend(evdev->dispatch, evdev); 718 break; 719 default: 720 return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; 721 } 722 723 pad->sendevents.current_mode = mode; 724 725 return LIBINPUT_CONFIG_STATUS_SUCCESS; 726} 727 728static enum libinput_config_send_events_mode 729pad_sendevents_get_mode(struct libinput_device *device) 730{ 731 struct evdev_device *evdev = evdev_device(device); 732 struct pad_dispatch *dispatch = (struct pad_dispatch*)evdev->dispatch; 733 734 return dispatch->sendevents.current_mode; 735} 736 737static enum libinput_config_send_events_mode 738pad_sendevents_get_default_mode(struct libinput_device *device) 739{ 740 return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; 741} 742 743struct evdev_dispatch * 744evdev_tablet_pad_create(struct evdev_device *device) 745{ 746 struct pad_dispatch *pad; 747 748 pad = zalloc(sizeof *pad); 749 750 if (pad_init(pad, device) != 0) { 751 pad_destroy(&pad->base); 752 return NULL; 753 } 754 755 device->base.config.sendevents = &pad->sendevents.config; 756 pad->sendevents.current_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; 757 pad->sendevents.config.get_modes = pad_sendevents_get_modes; 758 pad->sendevents.config.set_mode = pad_sendevents_set_mode; 759 pad->sendevents.config.get_mode = pad_sendevents_get_mode; 760 pad->sendevents.config.get_default_mode = pad_sendevents_get_default_mode; 761 762 return &pad->base; 763} 764 765int 766evdev_device_tablet_pad_has_key(struct evdev_device *device, uint32_t code) 767{ 768 if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD)) 769 return -1; 770 771 return libevdev_has_event_code(device->evdev, EV_KEY, code); 772} 773 774int 775evdev_device_tablet_pad_get_num_buttons(struct evdev_device *device) 776{ 777 struct pad_dispatch *pad = (struct pad_dispatch*)device->dispatch; 778 779 if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD)) 780 return -1; 781 782 return pad->nbuttons; 783} 784 785int 786evdev_device_tablet_pad_get_num_rings(struct evdev_device *device) 787{ 788 int nrings = 0; 789 790 if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD)) 791 return -1; 792 793 if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_WHEEL)) { 794 nrings++; 795 if (libevdev_has_event_code(device->evdev, 796 EV_ABS, 797 ABS_THROTTLE)) 798 nrings++; 799 } 800 801 return nrings; 802} 803 804int 805evdev_device_tablet_pad_get_num_strips(struct evdev_device *device) 806{ 807 int nstrips = 0; 808 809 if (!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD)) 810 return -1; 811 812 if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_RX)) { 813 nstrips++; 814 if (libevdev_has_event_code(device->evdev, 815 EV_ABS, 816 ABS_RY)) 817 nstrips++; 818 } 819 820 return nstrips; 821} 822