• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * expose input properties via udev
3  *
4  * Copyright (C) 2009 Martin Pitt <martin.pitt@ubuntu.com>
5  * Portions Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
6  * Copyright (C) 2011 Kay Sievers <kay@vrfy.org>
7  * Copyright (C) 2014 Carlos Garnacho <carlosg@gnome.org>
8  * Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <linux/limits.h>
31 #include <linux/input.h>
32 
33 #include "udev.h"
34 #include "util.h"
35 #include "missing.h"
36 
37 /* we must use this kernel-compatible implementation */
38 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
39 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
40 #define OFF(x)  ((x)%BITS_PER_LONG)
41 #define BIT(x)  (1UL<<OFF(x))
42 #define LONG(x) ((x)/BITS_PER_LONG)
43 #define test_bit(bit, array)    ((array[LONG(bit)] >> OFF(bit)) & 1)
44 
45 struct range {
46         unsigned start;
47         unsigned end;
48 };
49 
50 /* key code ranges above BTN_MISC (start is inclusive, stop is exclusive)*/
51 static const struct range high_key_blocks[] = {
52         { KEY_OK, BTN_DPAD_UP },
53         { KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY }
54 };
55 
abs_size_mm(const struct input_absinfo * absinfo)56 static inline int abs_size_mm(const struct input_absinfo *absinfo) {
57         /* Resolution is defined to be in units/mm for ABS_X/Y */
58         return (absinfo->maximum - absinfo->minimum) / absinfo->resolution;
59 }
60 
extract_info(struct udev_device * dev,const char * devpath,bool test)61 static void extract_info(struct udev_device *dev, const char *devpath, bool test) {
62         char width[DECIMAL_STR_MAX(int)], height[DECIMAL_STR_MAX(int)];
63         struct input_absinfo xabsinfo = {}, yabsinfo = {};
64         _cleanup_close_ int fd = -1;
65 
66         fd = open(devpath, O_RDONLY|O_CLOEXEC);
67         if (fd < 0)
68                 return;
69 
70         if (ioctl(fd, EVIOCGABS(ABS_X), &xabsinfo) < 0 ||
71             ioctl(fd, EVIOCGABS(ABS_Y), &yabsinfo) < 0)
72                 return;
73 
74         if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0)
75                 return;
76 
77         snprintf(width, sizeof(width), "%d", abs_size_mm(&xabsinfo));
78         snprintf(height, sizeof(height), "%d", abs_size_mm(&yabsinfo));
79 
80         udev_builtin_add_property(dev, test, "ID_INPUT_WIDTH_MM", width);
81         udev_builtin_add_property(dev, test, "ID_INPUT_HEIGHT_MM", height);
82 }
83 
84 /*
85  * Read a capability attribute and return bitmask.
86  * @param dev udev_device
87  * @param attr sysfs attribute name (e. g. "capabilities/key")
88  * @param bitmask: Output array which has a sizeof of bitmask_size
89  */
get_cap_mask(struct udev_device * dev,struct udev_device * pdev,const char * attr,unsigned long * bitmask,size_t bitmask_size,bool test)90 static void get_cap_mask(struct udev_device *dev,
91                          struct udev_device *pdev, const char* attr,
92                          unsigned long *bitmask, size_t bitmask_size,
93                          bool test) {
94         const char *v;
95         char text[4096];
96         unsigned i;
97         char* word;
98         unsigned long val;
99 
100         v = udev_device_get_sysattr_value(pdev, attr);
101         if (!v)
102                 v = "";
103 
104         snprintf(text, sizeof(text), "%s", v);
105         log_debug("%s raw kernel attribute: %s", attr, text);
106 
107         memzero(bitmask, bitmask_size);
108         i = 0;
109         while ((word = strrchr(text, ' ')) != NULL) {
110                 val = strtoul (word+1, NULL, 16);
111                 if (i < bitmask_size/sizeof(unsigned long))
112                         bitmask[i] = val;
113                 else
114                         log_debug("ignoring %s block %lX which is larger than maximum size", attr, val);
115                 *word = '\0';
116                 ++i;
117         }
118         val = strtoul (text, NULL, 16);
119         if (i < bitmask_size / sizeof(unsigned long))
120                 bitmask[i] = val;
121         else
122                 log_debug("ignoring %s block %lX which is larger than maximum size", attr, val);
123 
124         if (test) {
125                 /* printf pattern with the right unsigned long number of hex chars */
126                 snprintf(text, sizeof(text), "  bit %%4u: %%0%zulX\n",
127                          2 * sizeof(unsigned long));
128                 log_debug("%s decoded bit map:", attr);
129                 val = bitmask_size / sizeof (unsigned long);
130                 /* skip over leading zeros */
131                 while (bitmask[val-1] == 0 && val > 0)
132                         --val;
133                 for (i = 0; i < val; ++i) {
134                         DISABLE_WARNING_FORMAT_NONLITERAL;
135                         log_debug(text, i * BITS_PER_LONG, bitmask[i]);
136                         REENABLE_WARNING;
137                 }
138         }
139 }
140 
141 /* pointer devices */
test_pointers(struct udev_device * dev,const unsigned long * bitmask_ev,const unsigned long * bitmask_abs,const unsigned long * bitmask_key,const unsigned long * bitmask_rel,const unsigned long * bitmask_props,bool test)142 static bool test_pointers(struct udev_device *dev,
143                           const unsigned long* bitmask_ev,
144                           const unsigned long* bitmask_abs,
145                           const unsigned long* bitmask_key,
146                           const unsigned long* bitmask_rel,
147                           const unsigned long* bitmask_props,
148                           bool test) {
149         int button, axis;
150         bool has_abs_coordinates = false;
151         bool has_rel_coordinates = false;
152         bool has_mt_coordinates = false;
153         bool has_joystick_axes_or_buttons = false;
154         bool is_direct = false;
155         bool has_touch = false;
156         bool has_3d_coordinates = false;
157         bool has_keys = false;
158         bool stylus_or_pen = false;
159         bool finger_but_no_pen = false;
160         bool has_mouse_button = false;
161         bool is_mouse = false;
162         bool is_touchpad = false;
163         bool is_touchscreen = false;
164         bool is_tablet = false;
165         bool is_joystick = false;
166         bool is_accelerometer = false;
167         bool is_pointing_stick= false;
168 
169         has_keys = test_bit(EV_KEY, bitmask_ev);
170         has_abs_coordinates = test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs);
171         has_3d_coordinates = has_abs_coordinates && test_bit(ABS_Z, bitmask_abs);
172         is_accelerometer = test_bit(INPUT_PROP_ACCELEROMETER, bitmask_props);
173 
174         if (!has_keys && has_3d_coordinates)
175                 is_accelerometer = true;
176 
177         if (is_accelerometer) {
178                 udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1");
179                 return true;
180         }
181 
182         is_pointing_stick = test_bit(INPUT_PROP_POINTING_STICK, bitmask_props);
183         stylus_or_pen = test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key);
184         finger_but_no_pen = test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key);
185         for (button = BTN_MOUSE; button < BTN_JOYSTICK && !has_mouse_button; button++)
186                 has_mouse_button = test_bit(button, bitmask_key);
187         has_rel_coordinates = test_bit(EV_REL, bitmask_ev) && test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel);
188         has_mt_coordinates = test_bit(ABS_MT_POSITION_X, bitmask_abs) && test_bit(ABS_MT_POSITION_Y, bitmask_abs);
189 
190         /* unset has_mt_coordinates if devices claims to have all abs axis */
191         if (has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs))
192                 has_mt_coordinates = false;
193         is_direct = test_bit(INPUT_PROP_DIRECT, bitmask_props);
194         has_touch = test_bit(BTN_TOUCH, bitmask_key);
195 
196         /* joysticks don't necessarily have buttons; e. g.
197          * rudders/pedals are joystick-like, but buttonless; they have
198          * other fancy axes. Others have buttons only but no axes.
199          *
200          * The BTN_JOYSTICK range starts after the mouse range, so a mouse
201          * with more than 16 buttons runs into the joystick range (e.g. Mad
202          * Catz Mad Catz M.M.O.TE). Skip those.
203          */
204         if (!test_bit(BTN_JOYSTICK - 1, bitmask_key)) {
205                 for (button = BTN_JOYSTICK; button < BTN_DIGI && !has_joystick_axes_or_buttons; button++)
206                         has_joystick_axes_or_buttons = test_bit(button, bitmask_key);
207                 for (button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40 && !has_joystick_axes_or_buttons; button++)
208                         has_joystick_axes_or_buttons = test_bit(button, bitmask_key);
209                 for (button = BTN_DPAD_UP; button <= BTN_DPAD_RIGHT && !has_joystick_axes_or_buttons; button++)
210                         has_joystick_axes_or_buttons = test_bit(button, bitmask_key);
211         }
212         for (axis = ABS_RX; axis < ABS_PRESSURE && !has_joystick_axes_or_buttons; axis++)
213                 has_joystick_axes_or_buttons = test_bit(axis, bitmask_abs);
214 
215         if (has_abs_coordinates) {
216                 if (stylus_or_pen)
217                         is_tablet = true;
218                 else if (finger_but_no_pen && !is_direct)
219                         is_touchpad = true;
220                 else if (has_mouse_button)
221                         /* This path is taken by VMware's USB mouse, which has
222                          * absolute axes, but no touch/pressure button. */
223                         is_mouse = true;
224                 else if (has_touch || is_direct)
225                         is_touchscreen = true;
226                 else if (has_joystick_axes_or_buttons)
227                         is_joystick = true;
228         } else if (has_joystick_axes_or_buttons) {
229                 is_joystick = true;
230         }
231 
232         if (has_mt_coordinates) {
233                 if (stylus_or_pen)
234                         is_tablet = true;
235                 else if (finger_but_no_pen && !is_direct)
236                         is_touchpad = true;
237                 else if (has_touch || is_direct)
238                         is_touchscreen = true;
239         }
240 
241         if (!is_tablet && !is_touchpad && !is_joystick &&
242             has_mouse_button &&
243             (has_rel_coordinates ||
244             !has_abs_coordinates)) /* mouse buttons and no axis */
245                 is_mouse = true;
246 
247         if (is_pointing_stick)
248                 udev_builtin_add_property(dev, test, "ID_INPUT_POINTINGSTICK", "1");
249         if (is_mouse)
250                 udev_builtin_add_property(dev, test, "ID_INPUT_MOUSE", "1");
251         if (is_touchpad)
252                 udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHPAD", "1");
253         if (is_touchscreen)
254                 udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1");
255         if (is_joystick)
256                 udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1");
257         if (is_tablet)
258                 udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1");
259 
260         return is_tablet || is_mouse || is_touchpad || is_touchscreen || is_joystick || is_pointing_stick;
261 }
262 
263 /* key like devices */
test_key(struct udev_device * dev,const unsigned long * bitmask_ev,const unsigned long * bitmask_key,bool test)264 static bool test_key(struct udev_device *dev,
265                      const unsigned long* bitmask_ev,
266                      const unsigned long* bitmask_key,
267                      bool test) {
268         unsigned i;
269         unsigned long found;
270         unsigned long mask;
271         bool ret = false;
272 
273         /* do we have any KEY_* capability? */
274         if (!test_bit(EV_KEY, bitmask_ev)) {
275                 log_debug("test_key: no EV_KEY capability");
276                 return false;
277         }
278 
279         /* only consider KEY_* here, not BTN_* */
280         found = 0;
281         for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) {
282                 found |= bitmask_key[i];
283                 log_debug("test_key: checking bit block %lu for any keys; found=%i", (unsigned long)i*BITS_PER_LONG, found > 0);
284         }
285         /* If there are no keys in the lower block, check the higher blocks */
286         if (!found) {
287                 unsigned block;
288                 for (block = 0; block < (sizeof(high_key_blocks) / sizeof(struct range)); ++block) {
289                         for (i = high_key_blocks[block].start; i < high_key_blocks[block].end; ++i) {
290                                 if (test_bit(i, bitmask_key)) {
291                                         log_debug("test_key: Found key %x in high block", i);
292                                         found = 1;
293                                         break;
294                                 }
295                         }
296                 }
297         }
298 
299         if (found > 0) {
300                 udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1");
301                 ret = true;
302         }
303 
304         /* the first 32 bits are ESC, numbers, and Q to D; if we have all of
305          * those, consider it a full keyboard; do not test KEY_RESERVED, though */
306         mask = 0xFFFFFFFE;
307         if ((bitmask_key[0] & mask) == mask) {
308                 udev_builtin_add_property(dev, test, "ID_INPUT_KEYBOARD", "1");
309                 ret = true;
310         }
311 
312         return ret;
313 }
314 
builtin_input_id(struct udev_device * dev,int argc,char * argv[],bool test)315 static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], bool test) {
316         struct udev_device *pdev;
317         unsigned long bitmask_ev[NBITS(EV_MAX)];
318         unsigned long bitmask_abs[NBITS(ABS_MAX)];
319         unsigned long bitmask_key[NBITS(KEY_MAX)];
320         unsigned long bitmask_rel[NBITS(REL_MAX)];
321         unsigned long bitmask_props[NBITS(INPUT_PROP_MAX)];
322         const char *sysname, *devnode;
323         bool is_pointer;
324         bool is_key;
325 
326         /* walk up the parental chain until we find the real input device; the
327          * argument is very likely a subdevice of this, like eventN */
328         pdev = dev;
329         while (pdev != NULL && udev_device_get_sysattr_value(pdev, "capabilities/ev") == NULL)
330                 pdev = udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
331 
332         if (pdev) {
333                 /* Use this as a flag that input devices were detected, so that this
334                  * program doesn't need to be called more than once per device */
335                 udev_builtin_add_property(dev, test, "ID_INPUT", "1");
336                 get_cap_mask(dev, pdev, "capabilities/ev", bitmask_ev, sizeof(bitmask_ev), test);
337                 get_cap_mask(dev, pdev, "capabilities/abs", bitmask_abs, sizeof(bitmask_abs), test);
338                 get_cap_mask(dev, pdev, "capabilities/rel", bitmask_rel, sizeof(bitmask_rel), test);
339                 get_cap_mask(dev, pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), test);
340                 get_cap_mask(dev, pdev, "properties", bitmask_props, sizeof(bitmask_props), test);
341                 is_pointer = test_pointers(dev, bitmask_ev, bitmask_abs,
342                                            bitmask_key, bitmask_rel,
343                                            bitmask_props, test);
344                 is_key = test_key(dev, bitmask_ev, bitmask_key, test);
345                 /* Some evdev nodes have only a scrollwheel */
346                 if (!is_pointer && !is_key && test_bit(EV_REL, bitmask_ev) &&
347                     (test_bit(REL_WHEEL, bitmask_rel) || test_bit(REL_HWHEEL, bitmask_rel)))
348                         udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1");
349                 if (test_bit(EV_SW, bitmask_ev))
350                         udev_builtin_add_property(dev, test, "ID_INPUT_SWITCH", "1");
351 
352         }
353 
354         devnode = udev_device_get_devnode(dev);
355         sysname = udev_device_get_sysname(dev);
356         if (devnode && sysname && startswith(sysname, "event"))
357                 extract_info(dev, devnode, test);
358 
359         return EXIT_SUCCESS;
360 }
361 
362 const struct udev_builtin udev_builtin_input_id = {
363         .name = "input_id",
364         .cmd = builtin_input_id,
365         .help = "Input device properties",
366 };
367