]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-3.12/multitouch-win8' into for-next
authorJiri Kosina <jkosina@suse.cz>
Tue, 27 Aug 2013 08:01:49 +0000 (10:01 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 27 Aug 2013 08:01:49 +0000 (10:01 +0200)
1  2 
drivers/hid/hid-core.c
drivers/hid/usbhid/hid-core.c
include/linux/hid.h

diff --combined drivers/hid/hid-core.c
index 3efe19f4deaed585548615e1fa1cb4fbc5ffeed7,660dce9641626a2b2361e78777143415d59b911e..75253265c274dd8f8fd4274d3d38670ebc568f8f
@@@ -450,7 -450,7 +450,7 @@@ static int hid_parser_local(struct hid_
                        }
                        parser->local.delimiter_depth--;
                }
 -              return 1;
 +              return 0;
  
        case HID_LOCAL_ITEM_TAG_USAGE:
  
@@@ -677,12 -677,61 +677,61 @@@ static u8 *fetch_item(__u8 *start, __u
        return NULL;
  }
  
- static void hid_scan_usage(struct hid_device *hid, u32 usage)
+ static void hid_scan_input_usage(struct hid_parser *parser, u32 usage)
  {
+       struct hid_device *hid = parser->device;
        if (usage == HID_DG_CONTACTID)
                hid->group = HID_GROUP_MULTITOUCH;
  }
  
+ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
+ {
+       if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
+           parser->global.report_size == 8)
+               parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
+ }
+ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
+ {
+       struct hid_device *hid = parser->device;
+       if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
+           type == HID_COLLECTION_PHYSICAL)
+               hid->group = HID_GROUP_SENSOR_HUB;
+ }
+ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
+ {
+       __u32 data;
+       int i;
+       data = item_udata(item);
+       switch (item->tag) {
+       case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+               hid_scan_collection(parser, data & 0xff);
+               break;
+       case HID_MAIN_ITEM_TAG_END_COLLECTION:
+               break;
+       case HID_MAIN_ITEM_TAG_INPUT:
+               for (i = 0; i < parser->local.usage_index; i++)
+                       hid_scan_input_usage(parser, parser->local.usage[i]);
+               break;
+       case HID_MAIN_ITEM_TAG_OUTPUT:
+               break;
+       case HID_MAIN_ITEM_TAG_FEATURE:
+               for (i = 0; i < parser->local.usage_index; i++)
+                       hid_scan_feature_usage(parser, parser->local.usage[i]);
+               break;
+       }
+       /* Reset the local parser environment */
+       memset(&parser->local, 0, sizeof(parser->local));
+       return 0;
+ }
  /*
   * Scan a report descriptor before the device is added to the bus.
   * Sets device groups and other properties that determine what driver
   */
  static int hid_scan_report(struct hid_device *hid)
  {
-       unsigned int page = 0, delim = 0;
+       struct hid_parser *parser;
+       struct hid_item item;
        __u8 *start = hid->dev_rdesc;
        __u8 *end = start + hid->dev_rsize;
-       unsigned int u, u_min = 0, u_max = 0;
-       struct hid_item item;
+       static int (*dispatch_type[])(struct hid_parser *parser,
+                                     struct hid_item *item) = {
+               hid_scan_main,
+               hid_parser_global,
+               hid_parser_local,
+               hid_parser_reserved
+       };
+       parser = vzalloc(sizeof(struct hid_parser));
+       if (!parser)
+               return -ENOMEM;
  
+       parser->device = hid;
        hid->group = HID_GROUP_GENERIC;
-       while ((start = fetch_item(start, end, &item)) != NULL) {
-               if (item.format != HID_ITEM_FORMAT_SHORT)
-                       return -EINVAL;
-               if (item.type == HID_ITEM_TYPE_GLOBAL) {
-                       if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
-                               page = item_udata(&item) << 16;
-               } else if (item.type == HID_ITEM_TYPE_LOCAL) {
-                       if (delim > 1)
-                               break;
-                       u = item_udata(&item);
-                       if (item.size <= 2)
-                               u += page;
-                       switch (item.tag) {
-                       case HID_LOCAL_ITEM_TAG_DELIMITER:
-                               delim += !!u;
-                               break;
-                       case HID_LOCAL_ITEM_TAG_USAGE:
-                               hid_scan_usage(hid, u);
-                               break;
-                       case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-                               u_min = u;
-                               break;
-                       case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-                               u_max = u;
-                               for (u = u_min; u <= u_max; u++)
-                                       hid_scan_usage(hid, u);
-                               break;
-                       }
-               } else if (page == HID_UP_SENSOR &&
-                       item.type == HID_ITEM_TYPE_MAIN &&
-                       item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
-                       (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
-                       hid->group = HID_GROUP_SENSOR_HUB;
-       }
  
+       /*
+        * The parsing is simpler than the one in hid_open_report() as we should
+        * be robust against hid errors. Those errors will be raised by
+        * hid_open_report() anyway.
+        */
+       while ((start = fetch_item(start, end, &item)) != NULL)
+               dispatch_type[item.type](parser, &item);
+       /*
+        * Handle special flags set during scanning.
+        */
+       if ((parser->scan_flags & HID_SCAN_FLAG_MT_WIN_8) &&
+           (hid->group == HID_GROUP_MULTITOUCH))
+               hid->group = HID_GROUP_MULTITOUCH_WIN_8;
+       vfree(parser);
        return 0;
  }
  
@@@ -1128,8 -1170,7 +1170,8 @@@ static void hid_output_field(const stru
  }
  
  /*
 - * Create a report.
 + * Create a report. 'data' has to be allocated using
 + * hid_alloc_report_buf() so that it has proper size.
   */
  
  void hid_output_report(struct hid_report *report, __u8 *data)
  }
  EXPORT_SYMBOL_GPL(hid_output_report);
  
 +/*
 + * Allocator for buffer that is going to be passed to hid_output_report()
 + */
 +u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
 +{
 +      /*
 +       * 7 extra bytes are necessary to achieve proper functionality
 +       * of implement() working on 8 byte chunks
 +       */
 +
 +      int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
 +
 +      return kmalloc(len, flags);
 +}
 +EXPORT_SYMBOL_GPL(hid_alloc_report_buf);
 +
  /*
   * Set a field value. The report this field belongs to has to be
   * created and transferred to the device, to set this value in the
@@@ -1564,9 -1589,6 +1606,9 @@@ static const struct hid_device_id hid_h
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
@@@ -2211,9 -2231,6 +2253,9 @@@ static const struct hid_device_id hid_m
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
 +      { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
index bd38cdfbbba64fbb9fe76b6307f436f3f63f02f9,55ea9c40140e45c5a1c902601e8aebd948b2ee54..44df131d390a0e5cbb92d5701cab2f01a872fc9a
@@@ -535,6 -535,7 +535,6 @@@ static void __usbhid_submit_report(stru
  {
        int head;
        struct usbhid_device *usbhid = hid->driver_data;
 -      int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
  
        if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
                return;
                        return;
                }
  
 -              usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
 +              usbhid->out[usbhid->outhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
                if (!usbhid->out[usbhid->outhead].raw_report) {
                        hid_warn(hid, "output queueing failed\n");
                        return;
        }
  
        if (dir == USB_DIR_OUT) {
 -              usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
 +              usbhid->ctrl[usbhid->ctrlhead].raw_report = hid_alloc_report_buf(report, GFP_ATOMIC);
                if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
                        hid_warn(hid, "control queueing failed\n");
                        return;
@@@ -648,6 -649,62 +648,6 @@@ static void usbhid_submit_report(struc
        spin_unlock_irqrestore(&usbhid->lock, flags);
  }
  
 -/* Workqueue routine to send requests to change LEDs */
 -static void hid_led(struct work_struct *work)
 -{
 -      struct usbhid_device *usbhid =
 -              container_of(work, struct usbhid_device, led_work);
 -      struct hid_device *hid = usbhid->hid;
 -      struct hid_field *field;
 -      unsigned long flags;
 -
 -      field = hidinput_get_led_field(hid);
 -      if (!field) {
 -              hid_warn(hid, "LED event field not found\n");
 -              return;
 -      }
 -
 -      spin_lock_irqsave(&usbhid->lock, flags);
 -      if (!test_bit(HID_DISCONNECTED, &usbhid->iofl)) {
 -              usbhid->ledcount = hidinput_count_leds(hid);
 -              hid_dbg(usbhid->hid, "New ledcount = %u\n", usbhid->ledcount);
 -              __usbhid_submit_report(hid, field->report, USB_DIR_OUT);
 -      }
 -      spin_unlock_irqrestore(&usbhid->lock, flags);
 -}
 -
 -static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 -{
 -      struct hid_device *hid = input_get_drvdata(dev);
 -      struct usbhid_device *usbhid = hid->driver_data;
 -      struct hid_field *field;
 -      unsigned long flags;
 -      int offset;
 -
 -      if (type == EV_FF)
 -              return input_ff_event(dev, type, code, value);
 -
 -      if (type != EV_LED)
 -              return -1;
 -
 -      if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
 -              hid_warn(dev, "event field not found\n");
 -              return -1;
 -      }
 -
 -      spin_lock_irqsave(&usbhid->lock, flags);
 -      hid_set_field(field, offset, value);
 -      spin_unlock_irqrestore(&usbhid->lock, flags);
 -
 -      /*
 -       * Defer performing requested LED action.
 -       * This is more likely gather all LED changes into a single URB.
 -       */
 -      schedule_work(&usbhid->led_work);
 -
 -      return 0;
 -}
 -
  static int usbhid_wait_io(struct hid_device *hid)
  {
        struct usbhid_device *usbhid = hid->driver_data;
@@@ -750,12 -807,17 +750,17 @@@ void usbhid_init_reports(struct hid_dev
  {
        struct hid_report *report;
        struct usbhid_device *usbhid = hid->driver_data;
+       struct hid_report_enum *report_enum;
        int err, ret;
  
-       list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
-               usbhid_submit_report(hid, report, USB_DIR_IN);
+       if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) {
+               report_enum = &hid->report_enum[HID_INPUT_REPORT];
+               list_for_each_entry(report, &report_enum->report_list, list)
+                       usbhid_submit_report(hid, report, USB_DIR_IN);
+       }
  
-       list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
+       report_enum = &hid->report_enum[HID_FEATURE_REPORT];
+       list_for_each_entry(report, &report_enum->report_list, list)
                usbhid_submit_report(hid, report, USB_DIR_IN);
  
        err = 0;
@@@ -800,7 -862,7 +805,7 @@@ static int hid_find_field_early(struct 
        return -1;
  }
  
 -void usbhid_set_leds(struct hid_device *hid)
 +static void usbhid_set_leds(struct hid_device *hid)
  {
        struct hid_field *field;
        int offset;
                usbhid_submit_report(hid, field->report, USB_DIR_OUT);
        }
  }
 -EXPORT_SYMBOL_GPL(usbhid_set_leds);
  
  /*
   * Traverse the supplied list of reports and find the longest
@@@ -1216,6 -1279,7 +1221,6 @@@ static struct hid_ll_driver usb_hid_dri
        .open = usbhid_open,
        .close = usbhid_close,
        .power = usbhid_power,
 -      .hidinput_input_event = usb_hidinput_input_event,
        .request = usbhid_request,
        .wait = usbhid_wait_io,
        .idle = usbhid_idle,
@@@ -1309,6 -1373,8 +1314,6 @@@ static int usbhid_probe(struct usb_inte
        setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
        spin_lock_init(&usbhid->lock);
  
 -      INIT_WORK(&usbhid->led_work, hid_led);
 -
        ret = hid_add_device(hid);
        if (ret) {
                if (ret != -ENODEV)
@@@ -1341,6 -1407,7 +1346,6 @@@ static void hid_cancel_delayed_stuff(st
  {
        del_timer_sync(&usbhid->io_retry);
        cancel_work_sync(&usbhid->reset_work);
 -      cancel_work_sync(&usbhid->led_work);
  }
  
  static void hid_cease_io(struct usbhid_device *usbhid)
@@@ -1460,17 -1527,15 +1465,17 @@@ static int hid_suspend(struct usb_inter
        struct usbhid_device *usbhid = hid->driver_data;
        int status = 0;
        bool driver_suspended = false;
 +      unsigned int ledcount;
  
        if (PMSG_IS_AUTO(message)) {
 +              ledcount = hidinput_count_leds(hid);
                spin_lock_irq(&usbhid->lock);   /* Sync with error handler */
                if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
                    && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
                    && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)
                    && !test_bit(HID_CTRL_RUNNING, &usbhid->iofl)
                    && !test_bit(HID_KEYS_PRESSED, &usbhid->iofl)
 -                  && (!usbhid->ledcount || ignoreled))
 +                  && (!ledcount || ignoreled))
                {
                        set_bit(HID_SUSPENDED, &usbhid->iofl);
                        spin_unlock_irq(&usbhid->lock);
diff --combined include/linux/hid.h
index 5a4e789b9e978dcbb7065bdd167dc7ab64f2c38a,bc132d2a20aad8333f7140e55575ce827df59a57..f60ecdb236dd261bc6f7cb101f8e619339cff750
@@@ -283,6 -283,7 +283,7 @@@ struct hid_item 
  #define HID_QUIRK_MULTI_INPUT                 0x00000040
  #define HID_QUIRK_HIDINPUT_FORCE              0x00000080
  #define HID_QUIRK_NO_EMPTY_INPUT              0x00000100
+ #define HID_QUIRK_NO_INIT_INPUT_REPORTS               0x00000200
  #define HID_QUIRK_SKIP_OUTPUT_REPORTS         0x00010000
  #define HID_QUIRK_FULLSPEED_INTERVAL          0x10000000
  #define HID_QUIRK_NO_INIT_REPORTS             0x20000000
  #define HID_GROUP_GENERIC                     0x0001
  #define HID_GROUP_MULTITOUCH                  0x0002
  #define HID_GROUP_SENSOR_HUB                  0x0003
+ #define HID_GROUP_MULTITOUCH_WIN_8            0x0004
  
  /*
   * This is the global environment of the parser. This information is
@@@ -456,7 -458,6 +458,7 @@@ struct hid_device {                                                        /* device rep
        enum hid_type type;                                             /* device type (mouse, kbd, ...) */
        unsigned country;                                               /* HID country */
        struct hid_report_enum report_enum[HID_REPORT_TYPES];
 +      struct work_struct led_work;                                    /* delayed LED worker */
  
        struct semaphore driver_lock;                                   /* protects the current driver, except during input */
        struct semaphore driver_input_lock;                             /* protects the current driver */
@@@ -533,6 -534,8 +535,8 @@@ static inline void hid_set_drvdata(stru
  #define HID_GLOBAL_STACK_SIZE 4
  #define HID_COLLECTION_STACK_SIZE 4
  
+ #define HID_SCAN_FLAG_MT_WIN_8                        0x00000001
  struct hid_parser {
        struct hid_global     global;
        struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
        unsigned              collection_stack[HID_COLLECTION_STACK_SIZE];
        unsigned              collection_stack_ptr;
        struct hid_device    *device;
+       unsigned              scan_flags;
  };
  
  struct hid_class_descriptor {
@@@ -745,7 -749,6 +750,7 @@@ struct hid_field *hidinput_get_led_fiel
  unsigned int hidinput_count_leds(struct hid_device *hid);
  __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
  void hid_output_report(struct hid_report *report, __u8 *data);
 +u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
  struct hid_device *hid_allocate_device(void);
  struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
  int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
@@@ -991,6 -994,7 +996,6 @@@ int hid_report_raw_event(struct hid_dev
  u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
  int usbhid_quirks_init(char **quirks_param);
  void usbhid_quirks_exit(void);
 -void usbhid_set_leds(struct hid_device *hid);
  
  #ifdef CONFIG_HID_PID
  int hid_pidff_init(struct hid_device *hid);