evdev: Add support for device quirks and implement axes swapping
[profile/ivi/weston.git] / src / evdev.c
index cc5af91..157264b 100644 (file)
@@ -30,6 +30,8 @@
 #include "compositor.h"
 #include "evdev.h"
 
+#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
+
 void
 evdev_led_update(struct evdev_device *device, enum weston_led leds)
 {
@@ -129,21 +131,41 @@ evdev_process_absolute_motion(struct evdev_device *device,
        const int screen_width = device->output->current->width;
        const int screen_height = device->output->current->height;
 
-       switch (e->code) {
-       case ABS_X:
-               device->abs.x =
-                       (e->value - device->abs.min_x) * screen_width /
-                       (device->abs.max_x - device->abs.min_x) +
-                       device->output->x;
-               device->pending_events |= EVDEV_ABSOLUTE_MOTION;
-               break;
-       case ABS_Y:
-               device->abs.y =
-                       (e->value - device->abs.min_y) * screen_height /
-                       (device->abs.max_y - device->abs.min_y) +
-                       device->output->y;
-               device->pending_events |= EVDEV_ABSOLUTE_MOTION;
-               break;
+       if (device->quirks & EVDEV_QUIRK_SWAP_AXES) {
+               switch (e->code) {
+               case ABS_X:
+                       device->abs.y =
+                               (e->value - device->abs.min_y) * screen_height /
+                               (device->abs.max_y - device->abs.min_y) +
+                               device->output->y;
+                       device->pending_events |= EVDEV_ABSOLUTE_MOTION;
+                       break;
+               case ABS_Y:
+                       device->abs.x =
+                               (e->value - device->abs.min_x) * screen_width /
+                               (device->abs.max_x - device->abs.min_x) +
+                               device->output->x;
+                       device->pending_events |= EVDEV_ABSOLUTE_MOTION;
+                       break;
+               }
+
+       } else {
+               switch (e->code) {
+               case ABS_X:
+                       device->abs.x =
+                               (e->value - device->abs.min_x) * screen_width /
+                               (device->abs.max_x - device->abs.min_x) +
+                               device->output->x;
+                       device->pending_events |= EVDEV_ABSOLUTE_MOTION;
+                       break;
+               case ABS_Y:
+                       device->abs.y =
+                               (e->value - device->abs.min_y) * screen_height /
+                               (device->abs.max_y - device->abs.min_y) +
+                               device->output->y;
+                       device->pending_events |= EVDEV_ABSOLUTE_MOTION;
+                       break;
+               }
        }
 }
 
@@ -161,17 +183,35 @@ evdev_process_relative(struct evdev_device *device,
                device->pending_events |= EVDEV_RELATIVE_MOTION;
                break;
        case REL_WHEEL:
-               notify_axis(device->seat,
-                             time,
-                             WL_POINTER_AXIS_VERTICAL_SCROLL,
-                             wl_fixed_from_int(e->value));
+               switch (e->value) {
+               case -1:
+                       /* Scroll down */
+               case 1:
+                       /* Scroll up */
+                       notify_axis(device->seat,
+                                   time,
+                                   WL_POINTER_AXIS_VERTICAL_SCROLL,
+                                   -1 * e->value * DEFAULT_AXIS_STEP_DISTANCE);
+                       break;
+               default:
+                       break;
+               }
                break;
        case REL_HWHEEL:
-               notify_axis(device->seat,
-                             time,
-                             WL_POINTER_AXIS_HORIZONTAL_SCROLL,
-                             wl_fixed_from_int(e->value));
-               break;
+               switch (e->value) {
+               case -1:
+                       /* Scroll left */
+               case 1:
+                       /* Scroll right */
+                       notify_axis(device->seat,
+                                   time,
+                                   WL_POINTER_AXIS_HORIZONTAL_SCROLL,
+                                   e->value * DEFAULT_AXIS_STEP_DISTANCE);
+                       break;
+               default:
+                       break;
+
+               }
        }
 }
 
@@ -214,9 +254,10 @@ evdev_flush_motion(struct evdev_device *device, uint32_t time)
 {
        struct weston_seat *master = device->seat;
 
-       if (!device->pending_events)
+       if (!(device->pending_events & EVDEV_SYN))
                return;
 
+       device->pending_events &= ~EVDEV_SYN;
        if (device->pending_events & EVDEV_RELATIVE_MOTION) {
                notify_motion(master, time,
                              master->seat.pointer->x + device->rel.dx,
@@ -272,6 +313,9 @@ fallback_process(struct evdev_dispatch *dispatch,
        case EV_KEY:
                evdev_process_key(device, event, time);
                break;
+       case EV_SYN:
+               device->pending_events |= EVDEV_SYN;
+               break;
        }
 }
 
@@ -361,7 +405,7 @@ evdev_device_data(int fd, uint32_t mask, void *data)
 }
 
 static int
-evdev_configure_device(struct evdev_device *device)
+evdev_handle_device(struct evdev_device *device)
 {
        struct input_absinfo absinfo;
        unsigned long ev_bits[NBITS(EV_MAX)];
@@ -396,12 +440,22 @@ evdev_configure_device(struct evdev_device *device)
                if (TEST_BIT(abs_bits, ABS_MT_SLOT)) {
                        ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_X),
                              &absinfo);
-                       device->abs.min_x = absinfo.minimum;
-                       device->abs.max_x = absinfo.maximum;
+                       if (device->quirks & EVDEV_QUIRK_SWAP_AXES) {
+                               device->abs.min_y = absinfo.minimum;
+                               device->abs.max_y = absinfo.maximum;
+                       } else {
+                               device->abs.min_x = absinfo.minimum;
+                               device->abs.max_x = absinfo.maximum;
+                       }
                        ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_Y),
                              &absinfo);
-                       device->abs.min_y = absinfo.minimum;
-                       device->abs.max_y = absinfo.maximum;
+                       if (device->quirks & EVDEV_QUIRK_SWAP_AXES) {
+                               device->abs.min_x = absinfo.minimum;
+                               device->abs.max_x = absinfo.maximum;
+                       } else {
+                               device->abs.min_y = absinfo.minimum;
+                               device->abs.max_y = absinfo.maximum;
+                       }
                        device->is_mt = 1;
                        device->mt.slot = 0;
                        device->caps |= EVDEV_TOUCH;
@@ -447,9 +501,15 @@ evdev_configure_device(struct evdev_device *device)
                weston_log("input device %s, %s "
                           "ignored: unsupported device type\n",
                           device->devname, device->devnode);
-               return -1;
+               return 0;
        }
 
+       return 1;
+}
+
+static int
+evdev_configure_device(struct evdev_device *device)
+{
        if ((device->caps &
             (EVDEV_MOTION_ABS | EVDEV_MOTION_REL | EVDEV_BUTTON))) {
                weston_seat_init_pointer(device->seat);
@@ -457,7 +517,8 @@ evdev_configure_device(struct evdev_device *device)
                           device->devname, device->devnode);
        }
        if ((device->caps & EVDEV_KEYBOARD)) {
-               weston_seat_init_keyboard(device->seat, NULL);
+               if (weston_seat_init_keyboard(device->seat, NULL) < 0)
+                       return -1;
                weston_log("input device %s, %s is a keyboard\n",
                           device->devname, device->devnode);
        }
@@ -499,6 +560,13 @@ evdev_device_create(struct weston_seat *seat, const char *path, int device_fd)
        ioctl(device->fd, EVIOCGNAME(sizeof(devname)), devname);
        device->devname = strdup(devname);
 
+       if (!evdev_handle_device(device)) {
+               free(device->devnode);
+               free(device->devname);
+               free(device);
+               return EVDEV_UNHANDLED_DEVICE;
+       }
+
        if (evdev_configure_device(device) == -1)
                goto err1;