From: Martin Pitt Date: Mon, 30 Nov 2009 17:38:43 +0000 (+0100) Subject: extras: Add input_id X-Git-Tag: 174~704 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a6cf7734015dfc4479f4fdd4585d8953979fe0b0;p=systemd extras: Add input_id input_id probes input/event devices for their class (keyboard, keys, mouse, touchpad, tablet, joystick). This is based on the corresponding hal code in hald/linux/device.c, input_test_{abs,rel,...}. This should provide enough functionality to get hal-less X.org working (which in particular needs to know exactly which devices are touchpads). Replace the brittle hacks in 60-persistent-input.rules with checking for the new ID_INPUT_* flags. This keeps the old ID_CLASS properties for now (but they are to be removed later on). Note: The current code has several hacks still, which are to be replaced with proper libudev calls later on. --- diff --git a/Makefile.am b/Makefile.am index 08ff1578..883cfc8c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -236,6 +236,12 @@ extras_floppy_create_floppy_devices_SOURCES = extras/floppy/create_floppy_device extras_floppy_create_floppy_devices_LDADD = libudev/libudev-private.la libexec_PROGRAMS += extras/floppy/create_floppy_devices +# ------------------------------------------------------------------------------ +# usb_id - USB device property import +# ------------------------------------------------------------------------------ +extras_input_id_input_id_SOURCES = extras/input_id/input_id.c +libexec_PROGRAMS += extras/input_id/input_id + # ------------------------------------------------------------------------------ # path_id - compose identifier of persistent elements of the parent buses # ------------------------------------------------------------------------------ diff --git a/extras/input_id/.gitignore b/extras/input_id/.gitignore new file mode 100644 index 00000000..4f33cba4 --- /dev/null +++ b/extras/input_id/.gitignore @@ -0,0 +1 @@ +input_id diff --git a/extras/input_id/input_id.c b/extras/input_id/input_id.c new file mode 100644 index 00000000..393a05d5 --- /dev/null +++ b/extras/input_id/input_id.c @@ -0,0 +1,154 @@ +/* + * input_id - input device classification + * + * Copyright (C) 2009 Martin Pitt + * Portions Copyright (C) 2004 David Zeuthen, + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with keymap; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include + +/* we must use this kernel-compatible implementation */ +#define BITS_PER_LONG (sizeof(unsigned long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<> OFF(bit)) & 1) + +/* + * Read a capabilities/name file and return bitmask. + * @param path File to open + * @param bitmask: Output array; must have max_size elements + */ +static void get_cap_mask (const char *path, unsigned long *bitmask, size_t max_size) +{ + FILE* f; + int i; + char text[4096]; + char* word; + unsigned long val; + + f = fopen(path, "r"); + if (f == NULL) { + perror("opening caps file"); + exit(1); + } + if (fgets(text, sizeof(text), f) == NULL) { + perror("fgets"); + exit(1); + } + fclose(f); + + memset (bitmask, 0, max_size); + i = 0; + while ((word = strrchr(text, ' ')) != NULL) { + val = strtoul (word+1, NULL, 16); + bitmask[i] = val; + *word = '\0'; + ++i; + } + val = strtoul (text, NULL, 16); + bitmask[i] = val; +} + +/* pointer devices */ +static void test_pointers (const unsigned long* bitmask_abs, const unsigned long* bitmask_key, const unsigned long* bitmask_rel) +{ + int is_mouse = 0; + int is_touchpad = 0; + + if (test_bit (ABS_PRESSURE, bitmask_abs)) + is_touchpad = 1; + + if (test_bit (ABS_X, bitmask_abs) && test_bit (ABS_Y, bitmask_abs)) { + if (test_bit (BTN_STYLUS, bitmask_key)) + puts("ID_INPUT_TABLET=1"); + else if (test_bit (BTN_TOUCH, bitmask_key)) + is_touchpad = 1; + else if (test_bit (BTN_TRIGGER, bitmask_key) || + test_bit (BTN_A, bitmask_key) || + test_bit (BTN_1, bitmask_key)) + puts("ID_INPUT_JOYSTICK=1"); + else if (test_bit (BTN_MOUSE, bitmask_key)) + /* This path is taken by VMware's USB mouse, which has + * absolute axes, but no touch/pressure button. */ + is_mouse = 1; + } + + if (test_bit (REL_X, bitmask_rel) && test_bit (REL_Y, bitmask_rel)) + is_mouse = 1; + + if (is_mouse) + puts("ID_INPUT_MOUSE=1"); + if (is_touchpad) + puts("ID_INPUT_TOUCHPAD=1"); +} + +/* key like devices */ +static void test_key (const unsigned long* bitmask_key) +{ + unsigned i; + unsigned long acc; + unsigned long mask; + + /* do we have any KEY_* capability? */ + acc = 0; + for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) + acc |= bitmask_key[i]; + if (acc > 0) + puts("ID_INPUT_KEY=1"); + + /* the first 32 bits are ESC, numbers, and Q to D; if we have all of + * those, consider it a full keyboard; do not test KEY_RESERVED, though */ + mask = 0xFFFFFFFE; + if ((bitmask_key[0] & mask) == mask) + puts("ID_INPUT_KEYBOARD=1"); +} + +int main (int argc, char** argv) +{ + char capfile[PATH_MAX]; + unsigned long bitmask_abs[NBITS(ABS_MAX)]; + unsigned long bitmask_key[NBITS(KEY_MAX)]; + unsigned long bitmask_rel[NBITS(REL_MAX)]; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + + /* Use this as a flag that input devices were detected, so that this + * program doesn't need to be called more than once per device */ + puts("ID_INPUT=1"); + + snprintf(capfile, sizeof(capfile), "/sys/%s/device/capabilities/abs", argv[1]); + get_cap_mask (capfile, bitmask_abs, sizeof (bitmask_abs)); + snprintf(capfile, sizeof(capfile), "/sys/%s/device/capabilities/rel", argv[1]); + get_cap_mask (capfile, bitmask_rel, sizeof (bitmask_rel)); + snprintf(capfile, sizeof(capfile), "/sys/%s/device/capabilities/key", argv[1]); + get_cap_mask (capfile, bitmask_key, sizeof (bitmask_key)); + + test_pointers(bitmask_abs, bitmask_key, bitmask_rel); + + test_key(bitmask_key); + + return 0; +} diff --git a/rules/rules.d/60-persistent-input.rules b/rules/rules.d/60-persistent-input.rules index c65517b8..08fe49bb 100644 --- a/rules/rules.d/60-persistent-input.rules +++ b/rules/rules.d/60-persistent-input.rules @@ -4,22 +4,18 @@ ACTION!="add|change", GOTO="persistent_input_end" SUBSYSTEM!="input", GOTO="persistent_input_end" KERNEL=="input[0-9]*", GOTO="persistent_input_end" -SUBSYSTEMS=="usb", IMPORT{program}="usb_id --export %p" +ENV{ID_INPUT}=="", IMPORT{program}="input_id %p" +SUBSYSTEMS=="usb", ENV{ID_BUS}=="", IMPORT{program}="usb_id --export %p" -# well defined boot-subclass usb devices -SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="01", ENV{ID_CLASS}="kbd", GOTO="serial" -SUBSYSTEMS=="usb", ATTRS{bInterfaceClass}=="03", ATTRS{bInterfaceProtocol}=="02", ENV{ID_CLASS}="mouse", GOTO="serial" +# backwards-compatibility ID_CLASS +ENV{ID_INPUT_KEYBOARD}=="?*", ENV{ID_CLASS}="kbd" +ENV{ID_INPUT_MOUSE}=="?*", ENV{ID_CLASS}="mouse" +ENV{ID_INPUT_JOYSTICK}=="?*", ENV{ID_CLASS}="joystick" -# other devices +# other device types which we need for persistent links DRIVERS=="pcspkr", ENV{ID_CLASS}="spkr", GOTO="serial" -DRIVERS=="atkbd", ENV{ID_CLASS}="kbd", GOTO="serial" -DRIVERS=="psmouse", ENV{ID_CLASS}="mouse", GOTO="serial" ATTRS{name}=="*dvb*|*DVB*|* IR *", ENV{ID_CLASS}="ir", GOTO="serial" -# joystick (ABS_X || ABS_WHEEL || ABS_THROTTLE) && !BTN_TOUCH && !BTN_DIGI -ATTRS{modalias}=="input:*-*a[068],*|input:*-*a*,[68],*m*", ATTRS{modalias}!="input:*-*k*14[0A],*r*", \ - ENV{ID_CLASS}="joystick", GOTO="serial" - # fill empty serial number LABEL="serial", ENV{ID_CLASS}=="?*", ENV{ID_SERIAL}=="", ENV{ID_SERIAL}="noserial"