aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-input.c
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2011-11-23 03:49:14 -0500
committerJiri Kosina <jkosina@suse.cz>2011-11-28 05:10:22 -0500
commit4f5ca836bef3dd3eb602152d5d712a513998264e (patch)
tree37c1c2ba43fdcadac3e7627b57999ebb0c71bee4 /drivers/hid/hid-input.c
parenta2b2c20ba2f6e22c065f401d63f7f883779cf642 (diff)
HID: hid-input: add support for HID devices reporting Battery Strength
Some HID devices, such as my Bluetooth mouse, report their battery strength as an event. Rather than passing it through as a strange absolute input event, this patch registers it with the power_supply subsystem as a battery, so that the device's Battery Strength can be reported to usermode. The battery appears in sysfs names /sys/class/power_supply/hid-<UNIQ>-battery, and it is a child of the battery-containing device, so it should be clear what it's the battery of. Unfortunately on my current Fedora 16 system, while the battery does appear in the UI, it is listed as a Laptop Battery with 0% charge (since it ignores the "capacity" property of the battery and instead computes it from the "energy*" fields, which we can't supply given the limited information contained within the HID Report). Still, this patch is the first step. Signed-off-by: Jeremy Fitzhardinge <jeremy@goop.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-input.c')
-rw-r--r--drivers/hid/hid-input.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 6e3252651ce3..2d96b782b203 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -271,6 +271,97 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
271 return logical_extents / physical_extents; 271 return logical_extents / physical_extents;
272} 272}
273 273
274#ifdef CONFIG_HID_BATTERY_STRENGTH
275static enum power_supply_property hidinput_battery_props[] = {
276 POWER_SUPPLY_PROP_PRESENT,
277 POWER_SUPPLY_PROP_ONLINE,
278 POWER_SUPPLY_PROP_CAPACITY,
279 POWER_SUPPLY_PROP_MODEL_NAME,
280};
281
282static int hidinput_get_battery_property(struct power_supply *psy,
283 enum power_supply_property prop,
284 union power_supply_propval *val)
285{
286 struct hid_device *dev = container_of(psy, struct hid_device, battery);
287 int ret = 0;
288
289 switch (prop) {
290 case POWER_SUPPLY_PROP_PRESENT:
291 case POWER_SUPPLY_PROP_ONLINE:
292 val->intval = 1;
293 break;
294
295 case POWER_SUPPLY_PROP_CAPACITY:
296 if (dev->battery_min < dev->battery_max &&
297 dev->battery_val >= dev->battery_min &&
298 dev->battery_val <= dev->battery_max)
299 val->intval = (100 * (dev->battery_val - dev->battery_min)) /
300 (dev->battery_max - dev->battery_min);
301 else
302 ret = -EINVAL;
303 break;
304
305 case POWER_SUPPLY_PROP_MODEL_NAME:
306 val->strval = dev->name;
307 break;
308
309 default:
310 ret = -EINVAL;
311 break;
312 }
313
314 return ret;
315}
316
317static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max)
318{
319 struct power_supply *battery = &dev->battery;
320 int ret;
321
322 if (battery->name != NULL)
323 return; /* already initialized? */
324
325 battery->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq);
326 if (battery->name == NULL)
327 return;
328
329 battery->type = POWER_SUPPLY_TYPE_BATTERY;
330 battery->properties = hidinput_battery_props;
331 battery->num_properties = ARRAY_SIZE(hidinput_battery_props);
332 battery->use_for_apm = 0;
333 battery->get_property = hidinput_get_battery_property;
334
335 dev->battery_min = min;
336 dev->battery_max = max;
337
338 ret = power_supply_register(&dev->dev, battery);
339 if (ret != 0) {
340 hid_warn(dev, "can't register power supply: %d\n", ret);
341 kfree(battery->name);
342 battery->name = NULL;
343 }
344}
345
346static void hidinput_cleanup_battery(struct hid_device *dev)
347{
348 if (!dev->battery.name)
349 return;
350
351 power_supply_unregister(&dev->battery);
352 kfree(dev->battery.name);
353 dev->battery.name = NULL;
354}
355#else /* !CONFIG_HID_BATTERY_STRENGTH */
356static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max)
357{
358}
359
360static void hidinput_cleanup_battery(struct hid_device *dev)
361{
362}
363#endif /* CONFIG_HID_BATTERY_STRENGTH */
364
274static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, 365static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
275 struct hid_usage *usage) 366 struct hid_usage *usage)
276{ 367{
@@ -629,6 +720,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
629 } 720 }
630 break; 721 break;
631 722
723 case HID_UP_GENDEVCTRLS:
724 if ((usage->hid & HID_USAGE) == 0x20) { /* Battery Strength */
725 hidinput_setup_battery(device,
726 field->logical_minimum,
727 field->logical_maximum);
728 goto ignore;
729 } else
730 goto unknown;
731 break;
732
632 case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ 733 case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
633 set_bit(EV_REP, input->evbit); 734 set_bit(EV_REP, input->evbit);
634 switch (usage->hid & HID_USAGE) { 735 switch (usage->hid & HID_USAGE) {
@@ -760,6 +861,13 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
760 861
761 input = field->hidinput->input; 862 input = field->hidinput->input;
762 863
864 if (usage->hid == HID_DC_BATTERYSTRENGTH) {
865 hid->battery_val = value;
866 hid_dbg(hid, "battery value is %d (range %d-%d)\n",
867 value, hid->battery_min, hid->battery_max);
868 return;
869 }
870
763 if (!usage->type) 871 if (!usage->type)
764 return; 872 return;
765 873
@@ -1016,6 +1124,8 @@ void hidinput_disconnect(struct hid_device *hid)
1016{ 1124{
1017 struct hid_input *hidinput, *next; 1125 struct hid_input *hidinput, *next;
1018 1126
1127 hidinput_cleanup_battery(hid);
1128
1019 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { 1129 list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
1020 list_del(&hidinput->list); 1130 list_del(&hidinput->list);
1021 input_unregister_device(hidinput->input); 1131 input_unregister_device(hidinput->input);