Input: introduce device properties
authorHenrik Rydberg <rydberg@euromail.se>
Sat, 18 Dec 2010 19:51:13 +0000 (20:51 +0100)
committerHenrik Rydberg <rydberg@euromail.se>
Mon, 20 Dec 2010 08:37:33 +0000 (09:37 +0100)
Today, userspace sets up an input device based on the data it emits.
This is not always enough; a tablet and a touchscreen may emit exactly
the same data, for instance, but the former should be set up with a
pointer whereas the latter does not need to. Recently, a new type of
touchpad has emerged where the buttons are under the pad, which
changes logic without changing the emitted data. This patch introduces
a new ioctl, EVIOCGPROP, which enables user access to a set of device
properties useful during setup. The properties are given as a bitmap
in the same fashion as the event types, and are also made available
via sysfs, uevent and /proc/bus/input/devices.

Acked-by: Ping Cheng <pingc@wacom.com>
Acked-by: Chase Douglas <chase.douglas@canonical.com>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
drivers/input/evdev.c
drivers/input/input.c
drivers/input/misc/uinput.c
include/linux/input.h
include/linux/uinput.h

index e3f7fc6f95657e2f4846cebc0efae905d309c31d..0cd97e8f0c9acee04ecec31fdcac05ea1ab1d4c3 100644 (file)
@@ -677,6 +677,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 #define EVIOC_MASK_SIZE(nr)    ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))
        switch (EVIOC_MASK_SIZE(cmd)) {
 
+       case EVIOCGPROP(0):
+               return bits_to_user(dev->propbit, INPUT_PROP_MAX,
+                                   size, p, compat_mode);
+
        case EVIOCGKEY(0):
                return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
 
index 37708d1d86ec2e518f35959b64d42ff7a67411a8..9ea713f4192b11f4ed2862bf98a6f6849b714092 100644 (file)
@@ -1095,6 +1095,8 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
                seq_printf(seq, "%s ", handle->name);
        seq_putc(seq, '\n');
 
+       input_seq_print_bitmap(seq, "PROP", dev->propbit, INPUT_PROP_MAX);
+
        input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX);
        if (test_bit(EV_KEY, dev->evbit))
                input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX);
@@ -1318,11 +1320,26 @@ static ssize_t input_dev_show_modalias(struct device *dev,
 }
 static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
 
+static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
+                             int max, int add_cr);
+
+static ssize_t input_dev_show_properties(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       struct input_dev *input_dev = to_input_dev(dev);
+       int len = input_print_bitmap(buf, PAGE_SIZE, input_dev->propbit,
+                                    INPUT_PROP_MAX, true);
+       return min_t(int, len, PAGE_SIZE);
+}
+static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL);
+
 static struct attribute *input_dev_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_phys.attr,
        &dev_attr_uniq.attr,
        &dev_attr_modalias.attr,
+       &dev_attr_properties.attr,
        NULL
 };
 
@@ -1522,6 +1539,8 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
        if (dev->uniq)
                INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq);
 
+       INPUT_ADD_HOTPLUG_BM_VAR("PROP=", dev->propbit, INPUT_PROP_MAX);
+
        INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX);
        if (test_bit(EV_KEY, dev->evbit))
                INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX);
index bea89722c4e92e4105d6d6d0df8585912459c469..82542a1c1098fb00c3d33769a21088f3f7eccd05 100644 (file)
@@ -680,6 +680,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
                        retval = uinput_set_bit(arg, swbit, SW_MAX);
                        break;
 
+               case UI_SET_PROPBIT:
+                       retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
+                       break;
+
                case UI_SET_PHYS:
                        if (udev->state == UIST_CREATED) {
                                retval = -EINVAL;
index b3a1e02080c0ba041383145faf9869e1c433dc7a..8d9c76cd3c432a4a59a4ea39a22a534a230f085e 100644 (file)
@@ -91,6 +91,7 @@ struct input_keymap_entry {
 #define EVIOCGNAME(len)                _IOC(_IOC_READ, 'E', 0x06, len)         /* get device name */
 #define EVIOCGPHYS(len)                _IOC(_IOC_READ, 'E', 0x07, len)         /* get physical location */
 #define EVIOCGUNIQ(len)                _IOC(_IOC_READ, 'E', 0x08, len)         /* get unique identifier */
+#define EVIOCGPROP(len)                _IOC(_IOC_READ, 'E', 0x09, len)         /* get device properties */
 
 #define EVIOCGKEY(len)         _IOC(_IOC_READ, 'E', 0x18, len)         /* get global key state */
 #define EVIOCGLED(len)         _IOC(_IOC_READ, 'E', 0x19, len)         /* get all LEDs */
@@ -107,6 +108,18 @@ struct input_keymap_entry {
 
 #define EVIOCGRAB              _IOW('E', 0x90, int)                    /* Grab/Release device */
 
+/*
+ * Device properties and quirks
+ */
+
+#define INPUT_PROP_POINTER             0x00    /* needs a pointer */
+#define INPUT_PROP_DIRECT              0x01    /* direct input devices */
+#define INPUT_PROP_BUTTONPAD           0x02    /* has button(s) under pad */
+#define INPUT_PROP_SEMI_MT             0x03    /* touch rectangle only */
+
+#define INPUT_PROP_MAX                 0x1f
+#define INPUT_PROP_CNT                 (INPUT_PROP_MAX + 1)
+
 /*
  * Event types
  */
@@ -1090,6 +1103,7 @@ struct ff_effect {
  * @phys: physical path to the device in the system hierarchy
  * @uniq: unique identification code for the device (if device has it)
  * @id: id of the device (struct input_id)
+ * @propbit: bitmap of device properties and quirks
  * @evbit: bitmap of types of events supported by the device (EV_KEY,
  *     EV_REL, etc.)
  * @keybit: bitmap of keys/buttons this device has
@@ -1173,6 +1187,8 @@ struct input_dev {
        const char *uniq;
        struct input_id id;
 
+       unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
+
        unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
        unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
        unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
index 05f7fed2b173eb8205b0754ee3a00de730215e8e..d28c726ede4f738680eedebc2944f0f73d698aa5 100644 (file)
@@ -104,6 +104,7 @@ struct uinput_ff_erase {
 #define UI_SET_FFBIT           _IOW(UINPUT_IOCTL_BASE, 107, int)
 #define UI_SET_PHYS            _IOW(UINPUT_IOCTL_BASE, 108, char*)
 #define UI_SET_SWBIT           _IOW(UINPUT_IOCTL_BASE, 109, int)
+#define UI_SET_PROPBIT         _IOW(UINPUT_IOCTL_BASE, 110, int)
 
 #define UI_BEGIN_FF_UPLOAD     _IOWR(UINPUT_IOCTL_BASE, 200, struct uinput_ff_upload)
 #define UI_END_FF_UPLOAD       _IOW(UINPUT_IOCTL_BASE, 201, struct uinput_ff_upload)