Skip to content

Commit 581c448

Browse files
dtorJiri Kosina
authored and
Jiri Kosina
committed
HID: input: map digitizer battery usage
We already mapped battery strength reports from the generic device control page, but we did not update capacity from input reports, nor we mapped the battery strength report from the digitizer page, so let's implement this now. Batteries driven by the input reports will now start in "unknown" state, and will get updated once we receive first report containing battery strength from the device. Signed-off-by: Dmitry Torokhov <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent a9d0683 commit 581c448

File tree

2 files changed

+127
-59
lines changed

2 files changed

+127
-59
lines changed

drivers/hid/hid-input.c

Lines changed: 125 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -340,13 +340,45 @@ static unsigned find_battery_quirk(struct hid_device *hdev)
340340
return quirks;
341341
}
342342

343+
static int hidinput_scale_battery_capacity(struct hid_device *dev,
344+
int value)
345+
{
346+
if (dev->battery_min < dev->battery_max &&
347+
value >= dev->battery_min && value <= dev->battery_max)
348+
value = ((value - dev->battery_min) * 100) /
349+
(dev->battery_max - dev->battery_min);
350+
351+
return value;
352+
}
353+
354+
static int hidinput_query_battery_capacity(struct hid_device *dev)
355+
{
356+
u8 *buf;
357+
int ret;
358+
359+
buf = kmalloc(2, GFP_KERNEL);
360+
if (!buf)
361+
return -ENOMEM;
362+
363+
ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
364+
dev->battery_report_type, HID_REQ_GET_REPORT);
365+
if (ret != 2) {
366+
kfree(buf);
367+
return -ENODATA;
368+
}
369+
370+
ret = hidinput_scale_battery_capacity(dev, buf[1]);
371+
kfree(buf);
372+
return ret;
373+
}
374+
343375
static int hidinput_get_battery_property(struct power_supply *psy,
344376
enum power_supply_property prop,
345377
union power_supply_propval *val)
346378
{
347379
struct hid_device *dev = power_supply_get_drvdata(psy);
380+
int value;
348381
int ret = 0;
349-
__u8 *buf;
350382

351383
switch (prop) {
352384
case POWER_SUPPLY_PROP_PRESENT:
@@ -355,37 +387,38 @@ static int hidinput_get_battery_property(struct power_supply *psy,
355387
break;
356388

357389
case POWER_SUPPLY_PROP_CAPACITY:
358-
359-
buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL);
360-
if (!buf) {
361-
ret = -ENOMEM;
362-
break;
363-
}
364-
ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
365-
dev->battery_report_type,
366-
HID_REQ_GET_REPORT);
367-
368-
if (ret != 2) {
369-
ret = -ENODATA;
370-
kfree(buf);
371-
break;
390+
if (dev->battery_report_type == HID_FEATURE_REPORT) {
391+
value = hidinput_query_battery_capacity(dev);
392+
if (value < 0)
393+
return value;
394+
} else {
395+
value = dev->battery_capacity;
372396
}
373-
ret = 0;
374397

375-
if (dev->battery_min < dev->battery_max &&
376-
buf[1] >= dev->battery_min &&
377-
buf[1] <= dev->battery_max)
378-
val->intval = (100 * (buf[1] - dev->battery_min)) /
379-
(dev->battery_max - dev->battery_min);
380-
kfree(buf);
398+
val->intval = value;
381399
break;
382400

383401
case POWER_SUPPLY_PROP_MODEL_NAME:
384402
val->strval = dev->name;
385403
break;
386404

387405
case POWER_SUPPLY_PROP_STATUS:
388-
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
406+
if (!dev->battery_reported &&
407+
dev->battery_report_type == HID_FEATURE_REPORT) {
408+
value = hidinput_query_battery_capacity(dev);
409+
if (value < 0)
410+
return value;
411+
412+
dev->battery_capacity = value;
413+
dev->battery_reported = true;
414+
}
415+
416+
if (!dev->battery_reported)
417+
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
418+
else if (dev->battery_capacity == 100)
419+
val->intval = POWER_SUPPLY_STATUS_FULL;
420+
else
421+
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
389422
break;
390423

391424
case POWER_SUPPLY_PROP_SCOPE:
@@ -400,35 +433,33 @@ static int hidinput_get_battery_property(struct power_supply *psy,
400433
return ret;
401434
}
402435

403-
static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
436+
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
404437
{
405-
struct power_supply_desc *psy_desc = NULL;
438+
struct power_supply_desc *psy_desc;
406439
struct power_supply_config psy_cfg = { .drv_data = dev, };
407440
unsigned quirks;
408441
s32 min, max;
442+
int error;
409443

410-
if (field->usage->hid != HID_DC_BATTERYSTRENGTH)
411-
return false; /* no match */
412-
413-
if (dev->battery != NULL)
414-
goto out; /* already initialized? */
444+
if (dev->battery)
445+
return 0; /* already initialized? */
415446

416447
quirks = find_battery_quirk(dev);
417448

418449
hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
419450
dev->bus, dev->vendor, dev->product, dev->version, quirks);
420451

421452
if (quirks & HID_BATTERY_QUIRK_IGNORE)
422-
goto out;
453+
return 0;
423454

424455
psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL);
425-
if (psy_desc == NULL)
426-
goto out;
456+
if (!psy_desc)
457+
return -ENOMEM;
427458

428459
psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq);
429-
if (psy_desc->name == NULL) {
430-
kfree(psy_desc);
431-
goto out;
460+
if (!psy_desc->name) {
461+
error = -ENOMEM;
462+
goto err_free_mem;
432463
}
433464

434465
psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
@@ -455,17 +486,20 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
455486

456487
dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
457488
if (IS_ERR(dev->battery)) {
458-
hid_warn(dev, "can't register power supply: %ld\n",
459-
PTR_ERR(dev->battery));
460-
kfree(psy_desc->name);
461-
kfree(psy_desc);
462-
dev->battery = NULL;
463-
} else {
464-
power_supply_powers(dev->battery, &dev->dev);
489+
error = PTR_ERR(dev->battery);
490+
hid_warn(dev, "can't register power supply: %d\n", error);
491+
goto err_free_name;
465492
}
466493

467-
out:
468-
return true;
494+
power_supply_powers(dev->battery, &dev->dev);
495+
return 0;
496+
497+
err_free_name:
498+
kfree(psy_desc->name);
499+
err_free_mem:
500+
kfree(psy_desc);
501+
dev->battery = NULL;
502+
return error;
469503
}
470504

471505
static void hidinput_cleanup_battery(struct hid_device *dev)
@@ -481,16 +515,33 @@ static void hidinput_cleanup_battery(struct hid_device *dev)
481515
kfree(psy_desc);
482516
dev->battery = NULL;
483517
}
518+
519+
static void hidinput_update_battery(struct hid_device *dev, int value)
520+
{
521+
if (!dev->battery)
522+
return;
523+
524+
if (value == 0 || value < dev->battery_min || value > dev->battery_max)
525+
return;
526+
527+
dev->battery_capacity = hidinput_scale_battery_capacity(dev, value);
528+
dev->battery_reported = true;
529+
power_supply_changed(dev->battery);
530+
}
484531
#else /* !CONFIG_HID_BATTERY_STRENGTH */
485-
static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
486-
struct hid_field *field)
532+
static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
533+
struct hid_field *field)
487534
{
488-
return false;
535+
return 0;
489536
}
490537

491538
static void hidinput_cleanup_battery(struct hid_device *dev)
492539
{
493540
}
541+
542+
static void hidinput_update_battery(struct hid_device *dev, int value)
543+
{
544+
}
494545
#endif /* CONFIG_HID_BATTERY_STRENGTH */
495546

496547
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
@@ -710,6 +761,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
710761
}
711762
break;
712763

764+
case 0x3b: /* Battery Strength */
765+
hidinput_setup_battery(device, HID_INPUT_REPORT, field);
766+
usage->type = EV_PWR;
767+
goto ignore;
768+
713769
case 0x3c: /* Invert */
714770
map_key_clear(BTN_TOOL_RUBBER);
715771
break;
@@ -944,11 +1000,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
9441000
break;
9451001

9461002
case HID_UP_GENDEVCTRLS:
947-
if (hidinput_setup_battery(device, HID_INPUT_REPORT, field))
1003+
switch (usage->hid) {
1004+
case HID_DC_BATTERYSTRENGTH:
1005+
hidinput_setup_battery(device, HID_INPUT_REPORT, field);
1006+
usage->type = EV_PWR;
9481007
goto ignore;
949-
else
950-
goto unknown;
951-
break;
1008+
}
1009+
goto unknown;
9521010

9531011
case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
9541012
set_bit(EV_REP, input->evbit);
@@ -1031,7 +1089,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
10311089
if (usage->code > max)
10321090
goto ignore;
10331091

1034-
10351092
if (usage->type == EV_ABS) {
10361093

10371094
int a = field->logical_minimum;
@@ -1090,14 +1147,19 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
10901147
struct input_dev *input;
10911148
unsigned *quirks = &hid->quirks;
10921149

1093-
if (!field->hidinput)
1150+
if (!usage->type)
10941151
return;
10951152

1096-
input = field->hidinput->input;
1153+
if (usage->type == EV_PWR) {
1154+
hidinput_update_battery(hid, value);
1155+
return;
1156+
}
10971157

1098-
if (!usage->type)
1158+
if (!field->hidinput)
10991159
return;
11001160

1161+
input = field->hidinput->input;
1162+
11011163
if (usage->hat_min < usage->hat_max || usage->hat_dir) {
11021164
int hat_dir = usage->hat_dir;
11031165
if (!hat_dir)
@@ -1373,6 +1435,7 @@ static void report_features(struct hid_device *hid)
13731435
struct hid_driver *drv = hid->driver;
13741436
struct hid_report_enum *rep_enum;
13751437
struct hid_report *rep;
1438+
struct hid_usage *usage;
13761439
int i, j;
13771440

13781441
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
@@ -1383,12 +1446,15 @@ static void report_features(struct hid_device *hid)
13831446
continue;
13841447

13851448
for (j = 0; j < rep->field[i]->maxusage; j++) {
1449+
usage = &rep->field[i]->usage[j];
1450+
13861451
/* Verify if Battery Strength feature is available */
1387-
hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
1452+
if (usage->hid == HID_DC_BATTERYSTRENGTH)
1453+
hidinput_setup_battery(hid, HID_FEATURE_REPORT,
1454+
rep->field[i]);
13881455

13891456
if (drv->feature_mapping)
1390-
drv->feature_mapping(hid, rep->field[i],
1391-
rep->field[i]->usage + j);
1457+
drv->feature_mapping(hid, rep->field[i], usage);
13921458
}
13931459
}
13941460
}

include/linux/hid.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,10 +542,12 @@ struct hid_device { /* device report descriptor */
542542
* battery is non-NULL.
543543
*/
544544
struct power_supply *battery;
545+
__s32 battery_capacity;
545546
__s32 battery_min;
546547
__s32 battery_max;
547548
__s32 battery_report_type;
548549
__s32 battery_report_id;
550+
bool battery_reported;
549551
#endif
550552

551553
unsigned int status; /* see STAT flags above */

0 commit comments

Comments
 (0)