hid-input/battery: add quirks for battery
authorJeremy Fitzhardinge <jeremy@goop.org>
Fri, 2 Dec 2011 19:12:36 +0000 (11:12 -0800)
committerJeremy Fitzhardinge <jeremy@goop.org>
Sun, 8 Jan 2012 07:30:37 +0000 (18:30 +1100)
Some devices always report percentage, despite having 0/255 as their
min/max, so add a quirk for them.

Signed-off-by: Jeremy Fitzhardinge <jeremy@goop.org>
drivers/hid/hid-core.c
drivers/hid/hid-input.c
include/linux/hid.h

index c0ef2b4..aa4a30b 100644 (file)
@@ -1157,7 +1157,7 @@ static bool hid_match_one_id(struct hid_device *hdev,
                (id->product == HID_ANY_ID || id->product == hdev->product);
 }
 
-static const struct hid_device_id *hid_match_id(struct hid_device *hdev,
+const struct hid_device_id *hid_match_id(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
        for (; id->bus; id++)
index b108ce7..69dec47 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/hid.h>
 #include <linux/hid-debug.h>
 
+#include "hid-ids.h"
+
 #define unk    KEY_UNKNOWN
 
 static const unsigned char hid_keyboard[256] = {
@@ -280,6 +282,28 @@ static enum power_supply_property hidinput_battery_props[] = {
        POWER_SUPPLY_PROP_STATUS
 };
 
+#define HID_BATTERY_QUIRK_PERCENT      (1 << 0) /* always reports percent */
+
+static const struct hid_device_id hid_battery_quirks[] = {
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE),
+         HID_BATTERY_QUIRK_PERCENT },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD),
+         HID_BATTERY_QUIRK_PERCENT },
+       {}
+};
+
+static unsigned find_battery_quirk(struct hid_device *hdev)
+{
+       unsigned quirks = 0;
+       const struct hid_device_id *match;
+
+       match = hid_match_id(hdev, hid_battery_quirks);
+       if (match != NULL)
+               quirks = match->driver_data;
+
+       return quirks;
+}
+
 static int hidinput_get_battery_property(struct power_supply *psy,
                                         enum power_supply_property prop,
                                         union power_supply_propval *val)
@@ -304,10 +328,11 @@ static int hidinput_get_battery_property(struct power_supply *psy,
                        break;
                }
 
-               /* store the returned value */
-               /* I'm not calculating this using the logical_minimum and maximum */
-               /* because my device returns 0-100 even though the min and max are 0-255 */
-               val->intval = buf[1];
+               if (dev->battery_min < dev->battery_max &&
+                   buf[1] >= dev->battery_min &&
+                   buf[1] <= dev->battery_max)
+                       val->intval = (100 * (buf[1] - dev->battery_min)) /
+                               (dev->battery_max - dev->battery_min);
                break;
 
        case POWER_SUPPLY_PROP_MODEL_NAME:
@@ -330,6 +355,7 @@ static void hidinput_setup_battery(struct hid_device *dev, unsigned id, s32 min,
 {
        struct power_supply *battery = &dev->battery;
        int ret;
+       unsigned quirks;
 
        if (battery->name != NULL)
                return;         /* already initialized? */
@@ -344,6 +370,13 @@ static void hidinput_setup_battery(struct hid_device *dev, unsigned id, s32 min,
        battery->use_for_apm = 0;
        battery->get_property = hidinput_get_battery_property;
 
+       quirks = find_battery_quirk(dev);
+
+       if (quirks & HID_BATTERY_QUIRK_PERCENT) {
+               min = 0;
+               max = 100;
+       }
+
        dev->battery_min = min;
        dev->battery_max = max;
        dev->battery_report_id = id;
index b5df198..fa772c8 100644 (file)
@@ -735,6 +735,8 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
 int hid_check_keys_pressed(struct hid_device *hid);
 int hid_connect(struct hid_device *hid, unsigned int connect_mask);
 void hid_disconnect(struct hid_device *hid);
+const struct hid_device_id *hid_match_id(struct hid_device *hdev,
+                                        const struct hid_device_id *id);
 
 /**
  * hid_map_usage - map usage input bits