Merge branch 'for-4.18/multitouch' into for-linus
[sfrench/cifs-2.6.git] / drivers / hid / hid-input.c
index 6836a856c243ab5c05ff7b1ff2f4af354fd34efb..ab93dd5927c3af344aeec911fe39bd3621bd787a 100644 (file)
@@ -387,7 +387,8 @@ static int hidinput_get_battery_property(struct power_supply *psy,
                break;
 
        case POWER_SUPPLY_PROP_CAPACITY:
-               if (dev->battery_report_type == HID_FEATURE_REPORT) {
+               if (dev->battery_status != HID_BATTERY_REPORTED &&
+                   !dev->battery_avoid_query) {
                        value = hidinput_query_battery_capacity(dev);
                        if (value < 0)
                                return value;
@@ -403,17 +404,17 @@ static int hidinput_get_battery_property(struct power_supply *psy,
                break;
 
        case POWER_SUPPLY_PROP_STATUS:
-               if (!dev->battery_reported &&
-                   dev->battery_report_type == HID_FEATURE_REPORT) {
+               if (dev->battery_status != HID_BATTERY_REPORTED &&
+                   !dev->battery_avoid_query) {
                        value = hidinput_query_battery_capacity(dev);
                        if (value < 0)
                                return value;
 
                        dev->battery_capacity = value;
-                       dev->battery_reported = true;
+                       dev->battery_status = HID_BATTERY_QUERIED;
                }
 
-               if (!dev->battery_reported)
+               if (dev->battery_status == HID_BATTERY_UNKNOWN)
                        val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
                else if (dev->battery_capacity == 100)
                        val->intval = POWER_SUPPLY_STATUS_FULL;
@@ -486,6 +487,14 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
        dev->battery_report_type = report_type;
        dev->battery_report_id = field->report->id;
 
+       /*
+        * Stylus is normally not connected to the device and thus we
+        * can't query the device and get meaningful battery strength.
+        * We have to wait for the device to report it on its own.
+        */
+       dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&
+                                  field->physical == HID_DG_STYLUS;
+
        dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
        if (IS_ERR(dev->battery)) {
                error = PTR_ERR(dev->battery);
@@ -530,9 +539,10 @@ static void hidinput_update_battery(struct hid_device *dev, int value)
 
        capacity = hidinput_scale_battery_capacity(dev, value);
 
-       if (!dev->battery_reported || capacity != dev->battery_capacity) {
+       if (dev->battery_status != HID_BATTERY_REPORTED ||
+           capacity != dev->battery_capacity) {
                dev->battery_capacity = capacity;
-               dev->battery_reported = true;
+               dev->battery_status = HID_BATTERY_REPORTED;
                power_supply_changed(dev->battery);
        }
 }
@@ -1100,8 +1110,31 @@ mapped:
 
        set_bit(usage->type, input->evbit);
 
-       while (usage->code <= max && test_and_set_bit(usage->code, bit))
-               usage->code = find_next_zero_bit(bit, max + 1, usage->code);
+       /*
+        * This part is *really* controversial:
+        * - HID aims at being generic so we should do our best to export
+        *   all incoming events
+        * - HID describes what events are, so there is no reason for ABS_X
+        *   to be mapped to ABS_Y
+        * - HID is using *_MISC+N as a default value, but nothing prevents
+        *   *_MISC+N to overwrite a legitimate even, which confuses userspace
+        *   (for instance ABS_MISC + 7 is ABS_MT_SLOT, which has a different
+        *   processing)
+        *
+        * If devices still want to use this (at their own risk), they will
+        * have to use the quirk HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE, but
+        * the default should be a reliable mapping.
+        */
+       while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
+               if (device->quirks & HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE) {
+                       usage->code = find_next_zero_bit(bit,
+                                                        max + 1,
+                                                        usage->code);
+               } else {
+                       device->status |= HID_STAT_DUP_DETECTED;
+                       goto ignore;
+               }
+       }
 
        if (usage->code > max)
                goto ignore;
@@ -1477,15 +1510,56 @@ static void report_features(struct hid_device *hid)
                }
 }
 
-static struct hid_input *hidinput_allocate(struct hid_device *hid)
+static struct hid_input *hidinput_allocate(struct hid_device *hid,
+                                          unsigned int application)
 {
        struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL);
        struct input_dev *input_dev = input_allocate_device();
-       if (!hidinput || !input_dev) {
-               kfree(hidinput);
-               input_free_device(input_dev);
-               hid_err(hid, "Out of memory during hid input probe\n");
-               return NULL;
+       const char *suffix = NULL;
+
+       if (!hidinput || !input_dev)
+               goto fail;
+
+       if ((hid->quirks & HID_QUIRK_INPUT_PER_APP) &&
+           hid->maxapplication > 1) {
+               switch (application) {
+               case HID_GD_KEYBOARD:
+                       suffix = "Keyboard";
+                       break;
+               case HID_GD_KEYPAD:
+                       suffix = "Keypad";
+                       break;
+               case HID_GD_MOUSE:
+                       suffix = "Mouse";
+                       break;
+               case HID_DG_STYLUS:
+                       suffix = "Pen";
+                       break;
+               case HID_DG_TOUCHSCREEN:
+                       suffix = "Touchscreen";
+                       break;
+               case HID_DG_TOUCHPAD:
+                       suffix = "Touchpad";
+                       break;
+               case HID_GD_SYSTEM_CONTROL:
+                       suffix = "System Control";
+                       break;
+               case HID_CP_CONSUMER_CONTROL:
+                       suffix = "Consumer Control";
+                       break;
+               case HID_GD_WIRELESS_RADIO_CTLS:
+                       suffix = "Wireless Radio Control";
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (suffix) {
+               hidinput->name = kasprintf(GFP_KERNEL, "%s %s",
+                                          hid->name, suffix);
+               if (!hidinput->name)
+                       goto fail;
        }
 
        input_set_drvdata(input_dev, hid);
@@ -1495,7 +1569,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
        input_dev->setkeycode = hidinput_setkeycode;
        input_dev->getkeycode = hidinput_getkeycode;
 
-       input_dev->name = hid->name;
+       input_dev->name = hidinput->name ? hidinput->name : hid->name;
        input_dev->phys = hid->phys;
        input_dev->uniq = hid->uniq;
        input_dev->id.bustype = hid->bus;
@@ -1503,10 +1577,19 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
        input_dev->id.product = hid->product;
        input_dev->id.version = hid->version;
        input_dev->dev.parent = &hid->dev;
+
        hidinput->input = input_dev;
        list_add_tail(&hidinput->list, &hid->inputs);
 
+       INIT_LIST_HEAD(&hidinput->reports);
+
        return hidinput;
+
+fail:
+       kfree(hidinput);
+       input_free_device(input_dev);
+       hid_err(hid, "Out of memory during hid input probe\n");
+       return NULL;
 }
 
 static bool hidinput_has_been_populated(struct hid_input *hidinput)
@@ -1552,6 +1635,7 @@ static void hidinput_cleanup_hidinput(struct hid_device *hid,
 
        list_del(&hidinput->list);
        input_free_device(hidinput->input);
+       kfree(hidinput->name);
 
        for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
                if (k == HID_OUTPUT_REPORT &&
@@ -1584,6 +1668,20 @@ static struct hid_input *hidinput_match(struct hid_report *report)
        return NULL;
 }
 
+static struct hid_input *hidinput_match_application(struct hid_report *report)
+{
+       struct hid_device *hid = report->device;
+       struct hid_input *hidinput;
+
+       list_for_each_entry(hidinput, &hid->inputs, list) {
+               if (hidinput->report &&
+                   hidinput->report->application == report->application)
+                       return hidinput;
+       }
+
+       return NULL;
+}
+
 static inline void hidinput_configure_usages(struct hid_input *hidinput,
                                             struct hid_report *report)
 {
@@ -1606,11 +1704,14 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
        struct hid_driver *drv = hid->driver;
        struct hid_report *report;
        struct hid_input *next, *hidinput = NULL;
+       unsigned int application;
        int i, k;
 
        INIT_LIST_HEAD(&hid->inputs);
        INIT_WORK(&hid->led_work, hidinput_led_worker);
 
+       hid->status &= ~HID_STAT_DUP_DETECTED;
+
        if (!force) {
                for (i = 0; i < hid->maxcollection; i++) {
                        struct hid_collection *col = &hid->collection[i];
@@ -1636,15 +1737,20 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                        if (!report->maxfield)
                                continue;
 
+                       application = report->application;
+
                        /*
                         * Find the previous hidinput report attached
                         * to this report id.
                         */
                        if (hid->quirks & HID_QUIRK_MULTI_INPUT)
                                hidinput = hidinput_match(report);
+                       else if (hid->maxapplication > 1 &&
+                                (hid->quirks & HID_QUIRK_INPUT_PER_APP))
+                               hidinput = hidinput_match_application(report);
 
                        if (!hidinput) {
-                               hidinput = hidinput_allocate(hid);
+                               hidinput = hidinput_allocate(hid, application);
                                if (!hidinput)
                                        goto out_unwind;
                        }
@@ -1653,6 +1759,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
 
                        if (hid->quirks & HID_QUIRK_MULTI_INPUT)
                                hidinput->report = report;
+
+                       list_add_tail(&report->hidinput_list,
+                                     &hidinput->reports);
                }
        }
 
@@ -1677,6 +1786,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                goto out_unwind;
        }
 
+       if (hid->status & HID_STAT_DUP_DETECTED)
+               hid_dbg(hid,
+                       "Some usages could not be mapped, please use HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE if this is legitimate.\n");
+
        return 0;
 
 out_unwind: