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