diff options
-rw-r--r-- | drivers/hid/hid-input.c | 61 | ||||
-rw-r--r-- | include/linux/hid.h | 1 |
2 files changed, 47 insertions, 15 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index b9b8c75a6f9a..8fac47cf42f1 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -277,6 +277,7 @@ static enum power_supply_property hidinput_battery_props[] = { | |||
277 | POWER_SUPPLY_PROP_ONLINE, | 277 | POWER_SUPPLY_PROP_ONLINE, |
278 | POWER_SUPPLY_PROP_CAPACITY, | 278 | POWER_SUPPLY_PROP_CAPACITY, |
279 | POWER_SUPPLY_PROP_MODEL_NAME, | 279 | POWER_SUPPLY_PROP_MODEL_NAME, |
280 | POWER_SUPPLY_PROP_STATUS | ||
280 | }; | 281 | }; |
281 | 282 | ||
282 | static int hidinput_get_battery_property(struct power_supply *psy, | 283 | static int hidinput_get_battery_property(struct power_supply *psy, |
@@ -285,6 +286,9 @@ static int hidinput_get_battery_property(struct power_supply *psy, | |||
285 | { | 286 | { |
286 | struct hid_device *dev = container_of(psy, struct hid_device, battery); | 287 | struct hid_device *dev = container_of(psy, struct hid_device, battery); |
287 | int ret = 0; | 288 | int ret = 0; |
289 | int ret_rep; | ||
290 | __u8 *buf = NULL; | ||
291 | unsigned char report_number = dev->battery_report_id; | ||
288 | 292 | ||
289 | switch (prop) { | 293 | switch (prop) { |
290 | case POWER_SUPPLY_PROP_PRESENT: | 294 | case POWER_SUPPLY_PROP_PRESENT: |
@@ -293,28 +297,45 @@ static int hidinput_get_battery_property(struct power_supply *psy, | |||
293 | break; | 297 | break; |
294 | 298 | ||
295 | case POWER_SUPPLY_PROP_CAPACITY: | 299 | case POWER_SUPPLY_PROP_CAPACITY: |
296 | if (dev->battery_min < dev->battery_max && | 300 | buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL); |
297 | dev->battery_val >= dev->battery_min && | 301 | if (!buf) { |
298 | dev->battery_val <= dev->battery_max) | 302 | ret = -ENOMEM; |
299 | val->intval = (100 * (dev->battery_val - dev->battery_min)) / | 303 | break; |
300 | (dev->battery_max - dev->battery_min); | 304 | } |
301 | else | 305 | |
306 | memset(buf, 0, sizeof(buf)); | ||
307 | ret_rep = dev->hid_get_raw_report(dev, report_number, buf, sizeof(buf), HID_FEATURE_REPORT); | ||
308 | if (ret_rep != 2) { | ||
302 | ret = -EINVAL; | 309 | ret = -EINVAL; |
310 | break; | ||
311 | } | ||
312 | |||
313 | /* store the returned value */ | ||
314 | /* I'm not calculating this using the logical_minimum and maximum */ | ||
315 | /* because my device returns 0-100 even though the min and max are 0-255 */ | ||
316 | val->intval = buf[1]; | ||
303 | break; | 317 | break; |
304 | 318 | ||
305 | case POWER_SUPPLY_PROP_MODEL_NAME: | 319 | case POWER_SUPPLY_PROP_MODEL_NAME: |
306 | val->strval = dev->name; | 320 | val->strval = dev->name; |
307 | break; | 321 | break; |
308 | 322 | ||
323 | case POWER_SUPPLY_PROP_STATUS: | ||
324 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
325 | break; | ||
326 | |||
309 | default: | 327 | default: |
310 | ret = -EINVAL; | 328 | ret = -EINVAL; |
311 | break; | 329 | break; |
312 | } | 330 | } |
313 | 331 | ||
332 | if (buf) { | ||
333 | kfree(buf); | ||
334 | } | ||
314 | return ret; | 335 | return ret; |
315 | } | 336 | } |
316 | 337 | ||
317 | static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | 338 | static void hidinput_setup_battery(struct hid_device *dev, unsigned id, s32 min, s32 max) |
318 | { | 339 | { |
319 | struct power_supply *battery = &dev->battery; | 340 | struct power_supply *battery = &dev->battery; |
320 | int ret; | 341 | int ret; |
@@ -326,7 +347,7 @@ static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | |||
326 | if (battery->name == NULL) | 347 | if (battery->name == NULL) |
327 | return; | 348 | return; |
328 | 349 | ||
329 | battery->type = POWER_SUPPLY_TYPE_BATTERY; | 350 | battery->type = POWER_SUPPLY_TYPE_USB; |
330 | battery->properties = hidinput_battery_props; | 351 | battery->properties = hidinput_battery_props; |
331 | battery->num_properties = ARRAY_SIZE(hidinput_battery_props); | 352 | battery->num_properties = ARRAY_SIZE(hidinput_battery_props); |
332 | battery->use_for_apm = 0; | 353 | battery->use_for_apm = 0; |
@@ -334,6 +355,7 @@ static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | |||
334 | 355 | ||
335 | dev->battery_min = min; | 356 | dev->battery_min = min; |
336 | dev->battery_max = max; | 357 | dev->battery_max = max; |
358 | dev->battery_report_id = id; | ||
337 | 359 | ||
338 | ret = power_supply_register(&dev->dev, battery); | 360 | ret = power_supply_register(&dev->dev, battery); |
339 | if (ret != 0) { | 361 | if (ret != 0) { |
@@ -353,7 +375,7 @@ static void hidinput_cleanup_battery(struct hid_device *dev) | |||
353 | dev->battery.name = NULL; | 375 | dev->battery.name = NULL; |
354 | } | 376 | } |
355 | #else /* !CONFIG_HID_BATTERY_STRENGTH */ | 377 | #else /* !CONFIG_HID_BATTERY_STRENGTH */ |
356 | static void hidinput_setup_battery(struct hid_device *dev, s32 min, s32 max) | 378 | static void hidinput_setup_battery(struct hid_device *dev, unsigned id, s32 min, s32 max) |
357 | { | 379 | { |
358 | } | 380 | } |
359 | 381 | ||
@@ -723,6 +745,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
723 | case HID_UP_GENDEVCTRLS: | 745 | case HID_UP_GENDEVCTRLS: |
724 | if ((usage->hid & HID_USAGE) == 0x20) { /* Battery Strength */ | 746 | if ((usage->hid & HID_USAGE) == 0x20) { /* Battery Strength */ |
725 | hidinput_setup_battery(device, | 747 | hidinput_setup_battery(device, |
748 | field->report->id, | ||
726 | field->logical_minimum, | 749 | field->logical_minimum, |
727 | field->logical_maximum); | 750 | field->logical_maximum); |
728 | goto ignore; | 751 | goto ignore; |
@@ -997,15 +1020,23 @@ static void report_features(struct hid_device *hid) | |||
997 | struct hid_report *rep; | 1020 | struct hid_report *rep; |
998 | int i, j; | 1021 | int i, j; |
999 | 1022 | ||
1000 | if (!drv->feature_mapping) | ||
1001 | return; | ||
1002 | |||
1003 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; | 1023 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; |
1004 | list_for_each_entry(rep, &rep_enum->report_list, list) | 1024 | list_for_each_entry(rep, &rep_enum->report_list, list) |
1005 | for (i = 0; i < rep->maxfield; i++) | 1025 | for (i = 0; i < rep->maxfield; i++) |
1006 | for (j = 0; j < rep->field[i]->maxusage; j++) | 1026 | for (j = 0; j < rep->field[i]->maxusage; j++) { |
1007 | drv->feature_mapping(hid, rep->field[i], | 1027 | /* Verify if Battery Strength feature is available */ |
1008 | rep->field[i]->usage + j); | 1028 | if (((rep->field[i]->usage + j)->hid & HID_USAGE_PAGE) == HID_UP_GENDEVCTRLS && |
1029 | ((rep->field[i]->usage + j)->hid & HID_USAGE) == 0x20) { | ||
1030 | hidinput_setup_battery(hid, | ||
1031 | rep->id, | ||
1032 | rep->field[i]->logical_minimum, | ||
1033 | rep->field[i]->logical_maximum); | ||
1034 | } | ||
1035 | |||
1036 | if (drv->feature_mapping) | ||
1037 | drv->feature_mapping(hid, rep->field[i], | ||
1038 | rep->field[i]->usage + j); | ||
1039 | } | ||
1009 | } | 1040 | } |
1010 | 1041 | ||
1011 | /* | 1042 | /* |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 7f344c3da767..b5df198d87a5 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -496,6 +496,7 @@ struct hid_device { /* device report descriptor */ | |||
496 | __s32 battery_min; | 496 | __s32 battery_min; |
497 | __s32 battery_max; | 497 | __s32 battery_max; |
498 | __s32 battery_val; | 498 | __s32 battery_val; |
499 | __s32 battery_report_id; | ||
499 | #endif | 500 | #endif |
500 | 501 | ||
501 | unsigned int status; /* see STAT flags above */ | 502 | unsigned int status; /* see STAT flags above */ |