]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-next' of git://github.com/rydberg/linux into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 1 Oct 2012 21:40:51 +0000 (14:40 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Mon, 1 Oct 2012 21:40:51 +0000 (14:40 -0700)
Merge Henrik's updates to multitouch code. Even though Jiri already
pulled them in I need to do it too since my changes to evdev using
dynamic major would clash with them.

1  2 
drivers/input/input.c
drivers/input/misc/uinput.c
drivers/input/tablet/wacom_wac.c

diff --combined drivers/input/input.c
index 768e46b05ef03eb6066a3a03ec0058938bcfc612,5244f3d05b12af769cf8c2d2a3010e17feb21f05..ace3f7c4226d60325fb11b1959fae61180cb3869
@@@ -47,6 -47,8 +47,8 @@@ static DEFINE_MUTEX(input_mutex)
  
  static struct input_handler *input_table[8];
  
+ static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 };
  static inline int is_event_supported(unsigned int code,
                                     unsigned long *bm, unsigned int max)
  {
@@@ -69,42 -71,102 +71,102 @@@ static int input_defuzz_abs_event(int v
        return value;
  }
  
+ static void input_start_autorepeat(struct input_dev *dev, int code)
+ {
+       if (test_bit(EV_REP, dev->evbit) &&
+           dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
+           dev->timer.data) {
+               dev->repeat_key = code;
+               mod_timer(&dev->timer,
+                         jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
+       }
+ }
+ static void input_stop_autorepeat(struct input_dev *dev)
+ {
+       del_timer(&dev->timer);
+ }
  /*
   * Pass event first through all filters and then, if event has not been
   * filtered out, through all open handles. This function is called with
   * dev->event_lock held and interrupts disabled.
   */
- static void input_pass_event(struct input_dev *dev,
-                            unsigned int type, unsigned int code, int value)
+ static unsigned int input_to_handler(struct input_handle *handle,
+                       struct input_value *vals, unsigned int count)
+ {
+       struct input_handler *handler = handle->handler;
+       struct input_value *end = vals;
+       struct input_value *v;
+       for (v = vals; v != vals + count; v++) {
+               if (handler->filter &&
+                   handler->filter(handle, v->type, v->code, v->value))
+                       continue;
+               if (end != v)
+                       *end = *v;
+               end++;
+       }
+       count = end - vals;
+       if (!count)
+               return 0;
+       if (handler->events)
+               handler->events(handle, vals, count);
+       else if (handler->event)
+               for (v = vals; v != end; v++)
+                       handler->event(handle, v->type, v->code, v->value);
+       return count;
+ }
+ /*
+  * Pass values first through all filters and then, if event has not been
+  * filtered out, through all open handles. This function is called with
+  * dev->event_lock held and interrupts disabled.
+  */
+ static void input_pass_values(struct input_dev *dev,
+                             struct input_value *vals, unsigned int count)
  {
-       struct input_handler *handler;
        struct input_handle *handle;
+       struct input_value *v;
+       if (!count)
+               return;
  
        rcu_read_lock();
  
        handle = rcu_dereference(dev->grab);
-       if (handle)
-               handle->handler->event(handle, type, code, value);
-       else {
-               bool filtered = false;
-               list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
-                       if (!handle->open)
-                               continue;
+       if (handle) {
+               count = input_to_handler(handle, vals, count);
+       } else {
+               list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+                       if (handle->open)
+                               count = input_to_handler(handle, vals, count);
+       }
  
-                       handler = handle->handler;
-                       if (!handler->filter) {
-                               if (filtered)
-                                       break;
+       rcu_read_unlock();
  
-                               handler->event(handle, type, code, value);
+       add_input_randomness(vals->type, vals->code, vals->value);
  
-                       } else if (handler->filter(handle, type, code, value))
-                               filtered = true;
+       /* trigger auto repeat for key events */
+       for (v = vals; v != vals + count; v++) {
+               if (v->type == EV_KEY && v->value != 2) {
+                       if (v->value)
+                               input_start_autorepeat(dev, v->code);
+                       else
+                               input_stop_autorepeat(dev);
                }
        }
+ }
  
-       rcu_read_unlock();
+ static void input_pass_event(struct input_dev *dev,
+                            unsigned int type, unsigned int code, int value)
+ {
+       struct input_value vals[] = { { type, code, value } };
+       input_pass_values(dev, vals, ARRAY_SIZE(vals));
  }
  
  /*
@@@ -121,18 -183,12 +183,12 @@@ static void input_repeat_key(unsigned l
  
        if (test_bit(dev->repeat_key, dev->key) &&
            is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
+               struct input_value vals[] =  {
+                       { EV_KEY, dev->repeat_key, 2 },
+                       input_value_sync
+               };
  
-               input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
-               if (dev->sync) {
-                       /*
-                        * Only send SYN_REPORT if we are not in a middle
-                        * of driver parsing a new hardware packet.
-                        * Otherwise assume that the driver will send
-                        * SYN_REPORT once it's done.
-                        */
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-               }
+               input_pass_values(dev, vals, ARRAY_SIZE(vals));
  
                if (dev->rep[REP_PERIOD])
                        mod_timer(&dev->timer, jiffies +
        spin_unlock_irqrestore(&dev->event_lock, flags);
  }
  
- static void input_start_autorepeat(struct input_dev *dev, int code)
- {
-       if (test_bit(EV_REP, dev->evbit) &&
-           dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
-           dev->timer.data) {
-               dev->repeat_key = code;
-               mod_timer(&dev->timer,
-                         jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
-       }
- }
- static void input_stop_autorepeat(struct input_dev *dev)
- {
-       del_timer(&dev->timer);
- }
  #define INPUT_IGNORE_EVENT    0
  #define INPUT_PASS_TO_HANDLERS        1
  #define INPUT_PASS_TO_DEVICE  2
+ #define INPUT_SLOT            4
+ #define INPUT_FLUSH           8
  #define INPUT_PASS_TO_ALL     (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
  
  static int input_handle_abs_event(struct input_dev *dev,
                                  unsigned int code, int *pval)
  {
+       struct input_mt *mt = dev->mt;
        bool is_mt_event;
        int *pold;
  
                 * "Stage" the event; we'll flush it later, when we
                 * get actual touch data.
                 */
-               if (*pval >= 0 && *pval < dev->mtsize)
-                       dev->slot = *pval;
+               if (mt && *pval >= 0 && *pval < mt->num_slots)
+                       mt->slot = *pval;
  
                return INPUT_IGNORE_EVENT;
        }
  
        if (!is_mt_event) {
                pold = &dev->absinfo[code].value;
-       } else if (dev->mt) {
-               struct input_mt_slot *mtslot = &dev->mt[dev->slot];
-               pold = &mtslot->abs[code - ABS_MT_FIRST];
+       } else if (mt) {
+               pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
        } else {
                /*
                 * Bypass filtering for multi-touch events when
        }
  
        /* Flush pending "slot" event */
-       if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
-               input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-               input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+       if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
+               input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
+               return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
        }
  
        return INPUT_PASS_TO_HANDLERS;
  }
  
- static void input_handle_event(struct input_dev *dev,
-                              unsigned int type, unsigned int code, int value)
+ static int input_get_disposition(struct input_dev *dev,
+                         unsigned int type, unsigned int code, int value)
  {
        int disposition = INPUT_IGNORE_EVENT;
  
                        break;
  
                case SYN_REPORT:
-                       if (!dev->sync) {
-                               dev->sync = true;
-                               disposition = INPUT_PASS_TO_HANDLERS;
-                       }
+                       disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH;
                        break;
                case SYN_MT_REPORT:
-                       dev->sync = false;
                        disposition = INPUT_PASS_TO_HANDLERS;
                        break;
                }
                break;
  
        case EV_KEY:
-               if (is_event_supported(code, dev->keybit, KEY_MAX) &&
-                   !!test_bit(code, dev->key) != value) {
+               if (is_event_supported(code, dev->keybit, KEY_MAX)) {
  
-                       if (value != 2) {
-                               __change_bit(code, dev->key);
-                               if (value)
-                                       input_start_autorepeat(dev, code);
-                               else
-                                       input_stop_autorepeat(dev);
+                       /* auto-repeat bypasses state updates */
+                       if (value == 2) {
+                               disposition = INPUT_PASS_TO_HANDLERS;
+                               break;
                        }
  
-                       disposition = INPUT_PASS_TO_HANDLERS;
+                       if (!!test_bit(code, dev->key) != !!value) {
+                               __change_bit(code, dev->key);
+                               disposition = INPUT_PASS_TO_HANDLERS;
+                       }
                }
                break;
  
        case EV_SW:
                if (is_event_supported(code, dev->swbit, SW_MAX) &&
-                   !!test_bit(code, dev->sw) != value) {
+                   !!test_bit(code, dev->sw) != !!value) {
  
                        __change_bit(code, dev->sw);
                        disposition = INPUT_PASS_TO_HANDLERS;
  
        case EV_LED:
                if (is_event_supported(code, dev->ledbit, LED_MAX) &&
-                   !!test_bit(code, dev->led) != value) {
+                   !!test_bit(code, dev->led) != !!value) {
  
                        __change_bit(code, dev->led);
                        disposition = INPUT_PASS_TO_ALL;
                break;
        }
  
-       if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-               dev->sync = false;
+       return disposition;
+ }
+ static void input_handle_event(struct input_dev *dev,
+                              unsigned int type, unsigned int code, int value)
+ {
+       int disposition;
+       disposition = input_get_disposition(dev, type, code, value);
  
        if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
                dev->event(dev, type, code, value);
  
-       if (disposition & INPUT_PASS_TO_HANDLERS)
-               input_pass_event(dev, type, code, value);
+       if (!dev->vals)
+               return;
+       if (disposition & INPUT_PASS_TO_HANDLERS) {
+               struct input_value *v;
+               if (disposition & INPUT_SLOT) {
+                       v = &dev->vals[dev->num_vals++];
+                       v->type = EV_ABS;
+                       v->code = ABS_MT_SLOT;
+                       v->value = dev->mt->slot;
+               }
+               v = &dev->vals[dev->num_vals++];
+               v->type = type;
+               v->code = code;
+               v->value = value;
+       }
+       if (disposition & INPUT_FLUSH) {
+               if (dev->num_vals >= 2)
+                       input_pass_values(dev, dev->vals, dev->num_vals);
+               dev->num_vals = 0;
+       } else if (dev->num_vals >= dev->max_vals - 2) {
+               dev->vals[dev->num_vals++] = input_value_sync;
+               input_pass_values(dev, dev->vals, dev->num_vals);
+               dev->num_vals = 0;
+       }
  }
  
  /**
@@@ -352,7 -425,6 +425,6 @@@ void input_event(struct input_dev *dev
        if (is_event_supported(type, dev->evbit, EV_MAX)) {
  
                spin_lock_irqsave(&dev->event_lock, flags);
-               add_input_randomness(type, code, value);
                input_handle_event(dev, type, code, value);
                spin_unlock_irqrestore(&dev->event_lock, flags);
        }
@@@ -831,10 -903,12 +903,12 @@@ int input_set_keycode(struct input_dev 
        if (test_bit(EV_KEY, dev->evbit) &&
            !is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
            __test_and_clear_bit(old_keycode, dev->key)) {
+               struct input_value vals[] =  {
+                       { EV_KEY, old_keycode, 0 },
+                       input_value_sync
+               };
  
-               input_pass_event(dev, EV_KEY, old_keycode, 0);
-               if (dev->sync)
-                       input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+               input_pass_values(dev, vals, ARRAY_SIZE(vals));
        }
  
   out:
  }
  EXPORT_SYMBOL(input_set_keycode);
  
 -#define MATCH_BIT(bit, max) \
 -              for (i = 0; i < BITS_TO_LONGS(max); i++) \
 -                      if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
 -                              break; \
 -              if (i != BITS_TO_LONGS(max)) \
 -                      continue;
 -
  static const struct input_device_id *input_match_device(struct input_handler *handler,
                                                        struct input_dev *dev)
  {
        const struct input_device_id *id;
 -      int i;
  
        for (id = handler->id_table; id->flags || id->driver_info; id++) {
  
                        if (id->version != dev->id.version)
                                continue;
  
 -              MATCH_BIT(evbit,  EV_MAX);
 -              MATCH_BIT(keybit, KEY_MAX);
 -              MATCH_BIT(relbit, REL_MAX);
 -              MATCH_BIT(absbit, ABS_MAX);
 -              MATCH_BIT(mscbit, MSC_MAX);
 -              MATCH_BIT(ledbit, LED_MAX);
 -              MATCH_BIT(sndbit, SND_MAX);
 -              MATCH_BIT(ffbit,  FF_MAX);
 -              MATCH_BIT(swbit,  SW_MAX);
 +              if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->keybit, dev->keybit, KEY_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX))
 +                      continue;
 +
 +              if (!bitmap_subset(id->swbit, dev->swbit, SW_MAX))
 +                      continue;
  
                if (!handler->match || handler->match(handler, dev))
                        return id;
@@@ -1425,6 -1490,7 +1499,7 @@@ static void input_dev_release(struct de
        input_ff_destroy(dev);
        input_mt_destroy_slots(dev);
        kfree(dev->absinfo);
+       kfree(dev->vals);
        kfree(dev);
  
        module_put(THIS_MODULE);
@@@ -1760,8 -1826,8 +1835,8 @@@ static unsigned int input_estimate_even
        int i;
        unsigned int events;
  
-       if (dev->mtsize) {
-               mt_slots = dev->mtsize;
+       if (dev->mt) {
+               mt_slots = dev->mt->num_slots;
        } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
                mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
                           dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
                if (test_bit(i, dev->relbit))
                        events++;
  
+       /* Make room for KEY and MSC events */
+       events += 7;
        return events;
  }
  
@@@ -1825,6 -1894,7 +1903,7 @@@ int input_register_device(struct input_
  {
        static atomic_t input_no = ATOMIC_INIT(0);
        struct input_handler *handler;
+       unsigned int packet_size;
        const char *path;
        int error;
  
        /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
        input_cleanse_bitmasks(dev);
  
-       if (!dev->hint_events_per_packet)
-               dev->hint_events_per_packet =
-                               input_estimate_events_per_packet(dev);
+       packet_size = input_estimate_events_per_packet(dev);
+       if (dev->hint_events_per_packet < packet_size)
+               dev->hint_events_per_packet = packet_size;
+       dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
+       dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
+       if (!dev->vals)
+               return -ENOMEM;
  
        /*
         * If delay and period are pre-set by the driver, then autorepeating
index 86328e9c98489dc890a665260f718fa13cab2d07,6b1797503e343a8cdae57e25ce84e9ac2dbe3a8c..a0a4bbaef02c242a8ee16e54bdb9337e8f80407e
@@@ -40,8 -40,7 +40,8 @@@
  #include <linux/input/mt.h>
  #include "../input-compat.h"
  
 -static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 +static int uinput_dev_event(struct input_dev *dev,
 +                          unsigned int type, unsigned int code, int value)
  {
        struct uinput_device    *udev = input_get_drvdata(dev);
  
  }
  
  /* Atomically allocate an ID for the given request. Returns 0 on success. */
 -static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
 +static bool uinput_request_alloc_id(struct uinput_device *udev,
 +                                  struct uinput_request *request)
  {
 -      int id;
 -      int err = -1;
 +      unsigned int id;
 +      bool reserved = false;
  
        spin_lock(&udev->requests_lock);
  
                if (!udev->requests[id]) {
                        request->id = id;
                        udev->requests[id] = request;
 -                      err = 0;
 +                      reserved = true;
                        break;
                }
        }
  
        spin_unlock(&udev->requests_lock);
 -      return err;
 +      return reserved;
  }
  
 -static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id)
 +static struct uinput_request *uinput_request_find(struct uinput_device *udev,
 +                                                unsigned int id)
  {
        /* Find an input request, by ID. Returns NULL if the ID isn't valid. */
 -      if (id >= UINPUT_NUM_REQUESTS || id < 0)
 +      if (id >= UINPUT_NUM_REQUESTS)
                return NULL;
  
        return udev->requests[id];
  }
  
 -static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request)
 +static int uinput_request_reserve_slot(struct uinput_device *udev,
 +                                     struct uinput_request *request)
  {
        /* Allocate slot. If none are available right away, wait. */
        return wait_event_interruptible(udev->requests_waitq,
 -                                      !uinput_request_alloc_id(udev, request));
 +                                      uinput_request_alloc_id(udev, request));
  }
  
 -static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request)
 +static void uinput_request_done(struct uinput_device *udev,
 +                              struct uinput_request *request)
  {
        /* Mark slot as available */
        udev->requests[request->id] = NULL;
        complete(&request->done);
  }
  
 -static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request)
 +static int uinput_request_send(struct uinput_device *udev,
 +                             struct uinput_request *request)
  {
        int retval;
  
 -      retval = uinput_request_reserve_slot(udev, request);
 -      if (retval)
 -              return retval;
 -
        retval = mutex_lock_interruptible(&udev->mutex);
        if (retval)
                return retval;
                goto out;
        }
  
 -      /* Tell our userspace app about this new request by queueing an input event */
 +      init_completion(&request->done);
 +
 +      /*
 +       * Tell our userspace application about this new request
 +       * by queueing an input event.
 +       */
        uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
  
   out:
        return retval;
  }
  
 +static int uinput_request_submit(struct uinput_device *udev,
 +                               struct uinput_request *request)
 +{
 +      int error;
 +
 +      error = uinput_request_reserve_slot(udev, request);
 +      if (error)
 +              return error;
 +
 +      error = uinput_request_send(udev, request);
 +      if (error) {
 +              uinput_request_done(udev, request);
 +              return error;
 +      }
 +
 +      wait_for_completion(&request->done);
 +      return request->retval;
 +}
 +
  /*
 - * Fail all ouitstanding requests so handlers don't wait for the userspace
 + * Fail all outstanding requests so handlers don't wait for the userspace
   * to finish processing them.
   */
  static void uinput_flush_requests(struct uinput_device *udev)
@@@ -189,12 -163,11 +189,12 @@@ static int uinput_dev_playback(struct i
        return uinput_dev_event(dev, EV_FF, effect_id, value);
  }
  
 -static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
 +static int uinput_dev_upload_effect(struct input_dev *dev,
 +                                  struct ff_effect *effect,
 +                                  struct ff_effect *old)
  {
        struct uinput_device *udev = input_get_drvdata(dev);
        struct uinput_request request;
 -      int retval;
  
        /*
         * uinput driver does not currently support periodic effects with
                        effect->u.periodic.waveform == FF_CUSTOM)
                return -EINVAL;
  
 -      request.id = -1;
 -      init_completion(&request.done);
        request.code = UI_FF_UPLOAD;
        request.u.upload.effect = effect;
        request.u.upload.old = old;
  
 -      retval = uinput_request_submit(udev, &request);
 -      if (!retval) {
 -              wait_for_completion(&request.done);
 -              retval = request.retval;
 -      }
 -
 -      return retval;
 +      return uinput_request_submit(udev, &request);
  }
  
  static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
  {
        struct uinput_device *udev = input_get_drvdata(dev);
        struct uinput_request request;
 -      int retval;
  
        if (!test_bit(EV_FF, dev->evbit))
                return -ENOSYS;
  
 -      request.id = -1;
 -      init_completion(&request.done);
        request.code = UI_FF_ERASE;
        request.u.effect_id = effect_id;
  
 -      retval = uinput_request_submit(udev, &request);
 -      if (!retval) {
 -              wait_for_completion(&request.done);
 -              retval = request.retval;
 -      }
 -
 -      return retval;
 +      return uinput_request_submit(udev, &request);
  }
  
  static void uinput_destroy_device(struct uinput_device *udev)
@@@ -357,8 -347,7 +357,8 @@@ static int uinput_allocate_device(struc
        return 0;
  }
  
 -static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count)
 +static int uinput_setup_device(struct uinput_device *udev,
 +                             const char __user *buffer, size_t count)
  {
        struct uinput_user_dev  *user_dev;
        struct input_dev        *dev;
                        goto exit;
                if (test_bit(ABS_MT_SLOT, dev->absbit)) {
                        int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
-                       input_mt_init_slots(dev, nslot);
+                       input_mt_init_slots(dev, nslot, 0);
                } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
                        input_set_events_per_packet(dev, 60);
                }
        return retval;
  }
  
 -static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count)
 +static ssize_t uinput_inject_event(struct uinput_device *udev,
 +                                 const char __user *buffer, size_t count)
  {
        struct input_event ev;
  
        return input_event_size();
  }
  
 -static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 +static ssize_t uinput_write(struct file *file, const char __user *buffer,
 +                          size_t count, loff_t *ppos)
  {
        struct uinput_device *udev = file->private_data;
        int retval;
  
 +      if (count == 0)
 +              return 0;
 +
        retval = mutex_lock_interruptible(&udev->mutex);
        if (retval)
                return retval;
        return retval;
  }
  
 -static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
 +static bool uinput_fetch_next_event(struct uinput_device *udev,
 +                                  struct input_event *event)
  {
 -      struct uinput_device *udev = file->private_data;
 -      int retval = 0;
 +      bool have_event;
  
 -      if (udev->state != UIST_CREATED)
 -              return -ENODEV;
 +      spin_lock_irq(&udev->dev->event_lock);
  
 -      if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK))
 -              return -EAGAIN;
 +      have_event = udev->head != udev->tail;
 +      if (have_event) {
 +              *event = udev->buff[udev->tail];
 +              udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
 +      }
  
 -      retval = wait_event_interruptible(udev->waitq,
 -                      udev->head != udev->tail || udev->state != UIST_CREATED);
 -      if (retval)
 -              return retval;
 +      spin_unlock_irq(&udev->dev->event_lock);
  
 -      retval = mutex_lock_interruptible(&udev->mutex);
 -      if (retval)
 -              return retval;
 +      return have_event;
 +}
  
 -      if (udev->state != UIST_CREATED) {
 -              retval = -ENODEV;
 -              goto out;
 -      }
 +static ssize_t uinput_events_to_user(struct uinput_device *udev,
 +                                   char __user *buffer, size_t count)
 +{
 +      struct input_event event;
 +      size_t read = 0;
  
 -      while (udev->head != udev->tail && retval + input_event_size() <= count) {
 -              if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) {
 -                      retval = -EFAULT;
 -                      goto out;
 -              }
 -              udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
 -              retval += input_event_size();
 +      while (read + input_event_size() <= count &&
 +             uinput_fetch_next_event(udev, &event)) {
 +
 +              if (input_event_to_user(buffer + read, &event))
 +                      return -EFAULT;
 +
 +              read += input_event_size();
        }
  
 - out:
 -      mutex_unlock(&udev->mutex);
 +      return read;
 +}
 +
 +static ssize_t uinput_read(struct file *file, char __user *buffer,
 +                         size_t count, loff_t *ppos)
 +{
 +      struct uinput_device *udev = file->private_data;
 +      ssize_t retval;
 +
 +      if (count != 0 && count < input_event_size())
 +              return -EINVAL;
 +
 +      do {
 +              retval = mutex_lock_interruptible(&udev->mutex);
 +              if (retval)
 +                      return retval;
 +
 +              if (udev->state != UIST_CREATED)
 +                      retval = -ENODEV;
 +              else if (udev->head == udev->tail &&
 +                       (file->f_flags & O_NONBLOCK))
 +                      retval = -EAGAIN;
 +              else
 +                      retval = uinput_events_to_user(udev, buffer, count);
 +
 +              mutex_unlock(&udev->mutex);
 +
 +              if (retval || count == 0)
 +                      break;
 +
 +              if (!(file->f_flags & O_NONBLOCK))
 +                      retval = wait_event_interruptible(udev->waitq,
 +                                                udev->head != udev->tail ||
 +                                                udev->state != UIST_CREATED);
 +      } while (retval == 0);
  
        return retval;
  }
@@@ -564,8 -516,8 +564,8 @@@ static int uinput_release(struct inode 
  
  #ifdef CONFIG_COMPAT
  struct uinput_ff_upload_compat {
 -      int                     request_id;
 -      int                     retval;
 +      __u32                   request_id;
 +      __s32                   retval;
        struct ff_effect_compat effect;
        struct ff_effect_compat old;
  };
@@@ -751,8 -703,7 +751,8 @@@ static long uinput_ioctl_handler(struc
                                break;
  
                        req = uinput_request_find(udev, ff_up.request_id);
 -                      if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) {
 +                      if (!req || req->code != UI_FF_UPLOAD ||
 +                          !req->u.upload.effect) {
                                retval = -EINVAL;
                                break;
                        }
@@@ -835,8 -786,7 +835,8 @@@ static long uinput_ioctl(struct file *f
  }
  
  #ifdef CONFIG_COMPAT
 -static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 +static long uinput_compat_ioctl(struct file *file,
 +                              unsigned int cmd, unsigned long arg)
  {
        return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
  }
@@@ -881,3 -831,4 +881,3 @@@ MODULE_VERSION("0.3")
  
  module_init(uinput_init);
  module_exit(uinput_exit);
 -
index 532d067a9e07a0745188eb3dab8e4025ef7b664f,5837d07e3c9ea60c788bfc37e1b336f5289efa85..2a81ce375f756d0989bd3a6592efc6641137e9a5
@@@ -1530,7 -1530,7 +1530,7 @@@ int wacom_setup_input_capabilities(stru
                        __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
                        __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
  
-                       input_mt_init_slots(input_dev, features->touch_max);
+                       input_mt_init_slots(input_dev, features->touch_max, 0);
  
                        input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
                                             0, 255, 0, 0);
  
        case TABLETPC2FG:
                if (features->device_type == BTN_TOOL_FINGER) {
-                       input_mt_init_slots(input_dev, features->touch_max);
+                       input_mt_init_slots(input_dev, features->touch_max, 0);
                        input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
                                        0, MT_TOOL_MAX, 0, 0);
                        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
  
                        __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
                        __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
-                       input_mt_init_slots(input_dev, features->touch_max);
+                       input_mt_init_slots(input_dev, features->touch_max, 0);
  
                        if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
                                __set_bit(BTN_TOOL_TRIPLETAP,
@@@ -1848,10 -1848,7 +1848,10 @@@ static const struct wacom_features waco
        { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS,  44704, 27940, 2047,
          63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
  static const struct wacom_features wacom_features_0xF4 =
 -      { "Wacom Cintiq 24HD",    WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
 +      { "Wacom Cintiq 24HD",       WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
 +        63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 +static const struct wacom_features wacom_features_0xF8 =
 +      { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS,   104480, 65600, 2047,
          63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
  static const struct wacom_features wacom_features_0x3F =
        { "Wacom Cintiq 21UX",    WACOM_PKGLEN_INTUOS,    87200, 65600, 1023,
@@@ -2094,7 -2091,6 +2094,7 @@@ const struct usb_device_id wacom_ids[] 
        { USB_DEVICE_WACOM(0xEF) },
        { USB_DEVICE_WACOM(0x47) },
        { USB_DEVICE_WACOM(0xF4) },
 +      { USB_DEVICE_WACOM(0xF8) },
        { USB_DEVICE_WACOM(0xFA) },
        { USB_DEVICE_LENOVO(0x6004) },
        { }