Merge branches 'for-4.13/multitouch', 'for-4.13/retrode', 'for-4.13/transport-open...
[sfrench/cifs-2.6.git] / drivers / hid / wacom_wac.c
index e274c9dc32f3a211d97d02f2b6477f20c9121fac..9f940293ede4109b3628e2aa72b1f872d0cc6072 100644 (file)
@@ -57,15 +57,18 @@ static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
 static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
 
 static void __wacom_notify_battery(struct wacom_battery *battery,
-                                  int bat_capacity, bool bat_charging,
-                                  bool bat_connected, bool ps_connected)
+                                  int bat_status, int bat_capacity,
+                                  bool bat_charging, bool bat_connected,
+                                  bool ps_connected)
 {
-       bool changed = battery->battery_capacity != bat_capacity  ||
+       bool changed = battery->bat_status       != bat_status    ||
+                      battery->battery_capacity != bat_capacity  ||
                       battery->bat_charging     != bat_charging  ||
                       battery->bat_connected    != bat_connected ||
                       battery->ps_connected     != ps_connected;
 
        if (changed) {
+               battery->bat_status = bat_status;
                battery->battery_capacity = bat_capacity;
                battery->bat_charging = bat_charging;
                battery->bat_connected = bat_connected;
@@ -77,13 +80,13 @@ static void __wacom_notify_battery(struct wacom_battery *battery,
 }
 
 static void wacom_notify_battery(struct wacom_wac *wacom_wac,
-       int bat_capacity, bool bat_charging, bool bat_connected,
-       bool ps_connected)
+       int bat_status, int bat_capacity, bool bat_charging,
+       bool bat_connected, bool ps_connected)
 {
        struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
 
-       __wacom_notify_battery(&wacom->battery, bat_capacity, bat_charging,
-                              bat_connected, ps_connected);
+       __wacom_notify_battery(&wacom->battery, bat_status, bat_capacity,
+                              bat_charging, bat_connected, ps_connected);
 }
 
 static int wacom_penpartner_irq(struct wacom_wac *wacom)
@@ -448,8 +451,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
                rw = (data[7] >> 2 & 0x07);
                battery_capacity = batcap_gr[rw];
                ps_connected = rw == 7;
-               wacom_notify_battery(wacom, battery_capacity, ps_connected,
-                                    1, ps_connected);
+               wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+                                    battery_capacity, ps_connected, 1,
+                                    ps_connected);
        }
 exit:
        return retval;
@@ -1071,7 +1075,8 @@ static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len)
                        wacom->led.groups[i].select = touch_ring_mode;
        }
 
-       __wacom_notify_battery(&remote->remotes[index].battery, bat_percent,
+       __wacom_notify_battery(&remote->remotes[index].battery,
+                               WACOM_POWER_SUPPLY_STATUS_AUTO, bat_percent,
                                bat_charging, 1, bat_charging);
 
 out:
@@ -1157,7 +1162,8 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
                bat_charging = (power_raw & 0x08) ? 1 : 0;
                ps_connected = (power_raw & 0x10) ? 1 : 0;
                battery_capacity = batcap_i4[power_raw & 0x07];
-               wacom_notify_battery(wacom, battery_capacity, bat_charging,
+               wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+                                    battery_capacity, bat_charging,
                                     battery_capacity || bat_charging,
                                     ps_connected);
                break;
@@ -1334,7 +1340,8 @@ static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom)
        bool chg = data[284] & 0x80;
        int battery_status = data[284] & 0x7F;
 
-       wacom_notify_battery(wacom, battery_status, chg, 1, chg);
+       wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+                            battery_status, chg, 1, chg);
 }
 
 static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len)
@@ -1696,20 +1703,92 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
        }
 }
 
-static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
+static void wacom_wac_battery_usage_mapping(struct hid_device *hdev,
                struct hid_field *field, struct hid_usage *usage)
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
        struct wacom_wac *wacom_wac = &wacom->wacom_wac;
        struct wacom_features *features = &wacom_wac->features;
-       struct input_dev *input = wacom_wac->pad_input;
        unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
 
        switch (equivalent_usage) {
+       case HID_DG_BATTERYSTRENGTH:
        case WACOM_HID_WD_BATTERY_LEVEL:
        case WACOM_HID_WD_BATTERY_CHARGING:
                features->quirks |= WACOM_QUIRK_BATTERY;
                break;
+       }
+}
+
+static void wacom_wac_battery_event(struct hid_device *hdev, struct hid_field *field,
+               struct hid_usage *usage, __s32 value)
+{
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+
+       switch (equivalent_usage) {
+       case HID_DG_BATTERYSTRENGTH:
+               if (value == 0) {
+                       wacom_wac->hid_data.bat_status = POWER_SUPPLY_STATUS_UNKNOWN;
+               }
+               else {
+                       value = value * 100 / (field->logical_maximum - field->logical_minimum);
+                       wacom_wac->hid_data.battery_capacity = value;
+                       wacom_wac->hid_data.bat_connected = 1;
+                       wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+               }
+               break;
+       case WACOM_HID_WD_BATTERY_LEVEL:
+               value = value * 100 / (field->logical_maximum - field->logical_minimum);
+               wacom_wac->hid_data.battery_capacity = value;
+               wacom_wac->hid_data.bat_connected = 1;
+               wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+               break;
+       case WACOM_HID_WD_BATTERY_CHARGING:
+               wacom_wac->hid_data.bat_charging = value;
+               wacom_wac->hid_data.ps_connected = value;
+               wacom_wac->hid_data.bat_connected = 1;
+               wacom_wac->hid_data.bat_status = WACOM_POWER_SUPPLY_STATUS_AUTO;
+               break;
+       }
+}
+
+static void wacom_wac_battery_pre_report(struct hid_device *hdev,
+               struct hid_report *report)
+{
+       return;
+}
+
+static void wacom_wac_battery_report(struct hid_device *hdev,
+               struct hid_report *report)
+{
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct wacom_features *features = &wacom_wac->features;
+
+       if (features->quirks & WACOM_QUIRK_BATTERY) {
+               int status = wacom_wac->hid_data.bat_status;
+               int capacity = wacom_wac->hid_data.battery_capacity;
+               bool charging = wacom_wac->hid_data.bat_charging;
+               bool connected = wacom_wac->hid_data.bat_connected;
+               bool powered = wacom_wac->hid_data.ps_connected;
+
+               wacom_notify_battery(wacom_wac, status, capacity, charging,
+                                    connected, powered);
+       }
+}
+
+static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
+               struct hid_field *field, struct hid_usage *usage)
+{
+       struct wacom *wacom = hid_get_drvdata(hdev);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct wacom_features *features = &wacom_wac->features;
+       struct input_dev *input = wacom_wac->pad_input;
+       unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
+
+       switch (equivalent_usage) {
        case WACOM_HID_WD_ACCELEROMETER_X:
                __set_bit(INPUT_PROP_ACCELEROMETER, input->propbit);
                wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 0);
@@ -1803,27 +1882,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
        }
 }
 
-static void wacom_wac_pad_battery_event(struct hid_device *hdev, struct hid_field *field,
-               struct hid_usage *usage, __s32 value)
-{
-       struct wacom *wacom = hid_get_drvdata(hdev);
-       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-       unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
-
-       switch (equivalent_usage) {
-       case WACOM_HID_WD_BATTERY_LEVEL:
-               wacom_wac->hid_data.battery_capacity = value;
-               wacom_wac->hid_data.bat_connected = 1;
-               break;
-
-       case WACOM_HID_WD_BATTERY_CHARGING:
-               wacom_wac->hid_data.bat_charging = value;
-               wacom_wac->hid_data.ps_connected = value;
-               wacom_wac->hid_data.bat_connected = 1;
-               break;
-       }
-}
-
 static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field,
                struct hid_usage *usage, __s32 value)
 {
@@ -1897,24 +1955,6 @@ static void wacom_wac_pad_pre_report(struct hid_device *hdev,
        wacom_wac->hid_data.inrange_state = 0;
 }
 
-static void wacom_wac_pad_battery_report(struct hid_device *hdev,
-               struct hid_report *report)
-{
-       struct wacom *wacom = hid_get_drvdata(hdev);
-       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
-       struct wacom_features *features = &wacom_wac->features;
-
-       if (features->quirks & WACOM_QUIRK_BATTERY) {
-               int capacity = wacom_wac->hid_data.battery_capacity;
-               bool charging = wacom_wac->hid_data.bat_charging;
-               bool connected = wacom_wac->hid_data.bat_connected;
-               bool powered = wacom_wac->hid_data.ps_connected;
-
-               wacom_notify_battery(wacom_wac, capacity, charging,
-                                    connected, powered);
-       }
-}
-
 static void wacom_wac_pad_report(struct hid_device *hdev,
                struct hid_report *report)
 {
@@ -1960,9 +2000,6 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
        case HID_DG_INRANGE:
                wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0);
                break;
-       case HID_DG_BATTERYSTRENGTH:
-               features->quirks |= WACOM_QUIRK_BATTERY;
-               break;
        case HID_DG_INVERT:
                wacom_map_usage(input, usage, field, EV_KEY,
                                BTN_TOOL_RUBBER, 0);
@@ -2035,10 +2072,6 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
                if (!(features->quirks & WACOM_QUIRK_SENSE))
                        wacom_wac->hid_data.sense_state = value;
                return;
-       case HID_DG_BATTERYSTRENGTH:
-               wacom_wac->hid_data.battery_capacity = value;
-               wacom_wac->hid_data.bat_connected = 1;
-               break;
        case HID_DG_INVERT:
                wacom_wac->hid_data.invert_state = value;
                return;
@@ -2077,28 +2110,28 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
                return;
        case WACOM_HID_WD_OFFSETLEFT:
                if (features->offset_left && value != features->offset_left)
-                       hid_warn(hdev, "%s: overriding exising left offset "
+                       hid_warn(hdev, "%s: overriding existing left offset "
                                 "%d -> %d\n", __func__, value,
                                 features->offset_left);
                features->offset_left = value;
                return;
        case WACOM_HID_WD_OFFSETRIGHT:
                if (features->offset_right && value != features->offset_right)
-                       hid_warn(hdev, "%s: overriding exising right offset "
+                       hid_warn(hdev, "%s: overriding existing right offset "
                                 "%d -> %d\n", __func__, value,
                                 features->offset_right);
                features->offset_right = value;
                return;
        case WACOM_HID_WD_OFFSETTOP:
                if (features->offset_top && value != features->offset_top)
-                       hid_warn(hdev, "%s: overriding exising top offset "
+                       hid_warn(hdev, "%s: overriding existing top offset "
                                 "%d -> %d\n", __func__, value,
                                 features->offset_top);
                features->offset_top = value;
                return;
        case WACOM_HID_WD_OFFSETBOTTOM:
                if (features->offset_bottom && value != features->offset_bottom)
-                       hid_warn(hdev, "%s: overriding exising bottom offset "
+                       hid_warn(hdev, "%s: overriding existing bottom offset "
                                 "%d -> %d\n", __func__, value,
                                 features->offset_bottom);
                features->offset_bottom = value;
@@ -2395,7 +2428,10 @@ void wacom_wac_usage_mapping(struct hid_device *hdev,
        if (WACOM_DIRECT_DEVICE(field))
                features->device_type |= WACOM_DEVICETYPE_DIRECT;
 
-       if (WACOM_PAD_FIELD(field))
+       /* usage tests must precede field tests */
+       if (WACOM_BATTERY_USAGE(usage))
+               wacom_wac_battery_usage_mapping(hdev, field, usage);
+       else if (WACOM_PAD_FIELD(field))
                wacom_wac_pad_usage_mapping(hdev, field, usage);
        else if (WACOM_PEN_FIELD(field))
                wacom_wac_pen_usage_mapping(hdev, field, usage);
@@ -2414,11 +2450,12 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field,
        if (value > field->logical_maximum || value < field->logical_minimum)
                return;
 
-       if (WACOM_PAD_FIELD(field)) {
-               wacom_wac_pad_battery_event(hdev, field, usage, value);
-               if (wacom->wacom_wac.pad_input)
-                       wacom_wac_pad_event(hdev, field, usage, value);
-       } else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+       /* usage tests must precede field tests */
+       if (WACOM_BATTERY_USAGE(usage))
+               wacom_wac_battery_event(hdev, field, usage, value);
+       else if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
+               wacom_wac_pad_event(hdev, field, usage, value);
+       else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
                wacom_wac_pen_event(hdev, field, usage, value);
        else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
                wacom_wac_finger_event(hdev, field, usage, value);
@@ -2452,6 +2489,8 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
        if (wacom_wac->features.type != HID_GENERIC)
                return;
 
+       wacom_wac_battery_pre_report(hdev, report);
+
        if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
                wacom_wac_pad_pre_report(hdev, report);
        else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
@@ -2471,11 +2510,11 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
        if (report->type != HID_INPUT_REPORT)
                return;
 
-       if (WACOM_PAD_FIELD(field)) {
-               wacom_wac_pad_battery_report(hdev, report);
-               if (wacom->wacom_wac.pad_input)
-                       wacom_wac_pad_report(hdev, report);
-       else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+       wacom_wac_battery_report(hdev, report);
+
+       if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
+               wacom_wac_pad_report(hdev, report);
+       else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
                wacom_wac_pen_report(hdev, report);
        else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
                wacom_wac_finger_report(hdev, report);
@@ -2813,13 +2852,14 @@ static int wacom_wireless_irq(struct wacom_wac *wacom, size_t len)
                        wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
                }
 
-               wacom_notify_battery(wacom, battery, charging, 1, 0);
+               wacom_notify_battery(wacom, WACOM_POWER_SUPPLY_STATUS_AUTO,
+                                    battery, charging, 1, 0);
 
        } else if (wacom->pid != 0) {
                /* disconnected while previously connected */
                wacom->pid = 0;
                wacom_schedule_work(wacom, WACOM_WORKER_WIRELESS);
-               wacom_notify_battery(wacom, 0, 0, 0, 0);
+               wacom_notify_battery(wacom, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
        }
 
        return 0;
@@ -2847,8 +2887,8 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
                int battery = (data[8] & 0x3f) * 100 / 31;
                bool charging = !!(data[8] & 0x80);
 
-               wacom_notify_battery(wacom_wac, battery, charging,
-                                    battery || charging, 1);
+               wacom_notify_battery(wacom_wac, WACOM_POWER_SUPPLY_STATUS_AUTO,
+                                    battery, charging, battery || charging, 1);
 
                if (!wacom->battery.battery &&
                    !(features->quirks & WACOM_QUIRK_BATTERY)) {
@@ -2860,7 +2900,7 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
                 wacom->battery.battery) {
                features->quirks &= ~WACOM_QUIRK_BATTERY;
                wacom_schedule_work(wacom_wac, WACOM_WORKER_BATTERY);
-               wacom_notify_battery(wacom_wac, 0, 0, 0, 0);
+               wacom_notify_battery(wacom_wac, POWER_SUPPLY_STATUS_UNKNOWN, 0, 0, 0, 0);
        }
        return 0;
 }