aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2017-03-27 10:59:36 -0400
committerJiri Kosina <jkosina@suse.cz>2017-04-06 08:36:39 -0400
commit5b036ea18e13e006e99cb197e9aceb09d897d20a (patch)
tree0bc7406942824db5f2c05e45dcdcbc15f393328d
parent14f437a1d7b49a2e873f63436526f9aed3a781c3 (diff)
HID: logitech-hidpp: battery: provide CAPACITY_LEVEL
CAPACITY LEVEL allows to forward rough information on the battery mileage. HID++ 2.0 devices will either report percentage or levels, so better forwarding this information to the user space. The M325 supports only 2 levels: 'Full' and 'Critical'. With mileage, it will report either 90% or 5%, which might confuse users. With this change the battery will either report "Full" or "Critical". Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Tested-by: Bastien Nocera <hadess@hadess.net> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-logitech-hidpp.c104
1 files changed, 94 insertions, 10 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index c59f7e5eedfa..d7dc45801226 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -68,6 +68,8 @@ MODULE_PARM_DESC(disable_tap_to_click,
68 68
69#define HIDPP_CAPABILITY_HIDPP10_BATTERY BIT(0) 69#define HIDPP_CAPABILITY_HIDPP10_BATTERY BIT(0)
70#define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1) 70#define HIDPP_CAPABILITY_HIDPP20_BATTERY BIT(1)
71#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
72#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
71 73
72/* 74/*
73 * There are two hidpp protocols in use, the first version hidpp10 is known 75 * There are two hidpp protocols in use, the first version hidpp10 is known
@@ -120,6 +122,7 @@ struct hidpp_battery {
120 char name[64]; 122 char name[64];
121 int status; 123 int status;
122 int capacity; 124 int capacity;
125 int level;
123 bool online; 126 bool online;
124}; 127};
125 128
@@ -683,13 +686,30 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
683 686
684#define EVENT_BATTERY_LEVEL_STATUS_BROADCAST 0x00 687#define EVENT_BATTERY_LEVEL_STATUS_BROADCAST 0x00
685 688
689#define FLAG_BATTERY_LEVEL_DISABLE_OSD BIT(0)
690#define FLAG_BATTERY_LEVEL_MILEAGE BIT(1)
691#define FLAG_BATTERY_LEVEL_RECHARGEABLE BIT(2)
692
693static int hidpp_map_battery_level(int capacity)
694{
695 if (capacity < 11)
696 return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
697 else if (capacity < 31)
698 return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
699 else if (capacity < 81)
700 return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
701 return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
702}
703
686static int hidpp20_batterylevel_map_status_capacity(u8 data[3], int *capacity, 704static int hidpp20_batterylevel_map_status_capacity(u8 data[3], int *capacity,
687 int *next_capacity) 705 int *next_capacity,
706 int *level)
688{ 707{
689 int status; 708 int status;
690 709
691 *capacity = data[0]; 710 *capacity = data[0];
692 *next_capacity = data[1]; 711 *next_capacity = data[1];
712 *level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
693 713
694 /* When discharging, we can rely on the device reported capacity. 714 /* When discharging, we can rely on the device reported capacity.
695 * For all other states the device reports 0 (unknown). 715 * For all other states the device reports 0 (unknown).
@@ -697,6 +717,7 @@ static int hidpp20_batterylevel_map_status_capacity(u8 data[3], int *capacity,
697 switch (data[2]) { 717 switch (data[2]) {
698 case 0: /* discharging (in use) */ 718 case 0: /* discharging (in use) */
699 status = POWER_SUPPLY_STATUS_DISCHARGING; 719 status = POWER_SUPPLY_STATUS_DISCHARGING;
720 *level = hidpp_map_battery_level(*capacity);
700 break; 721 break;
701 case 1: /* recharging */ 722 case 1: /* recharging */
702 status = POWER_SUPPLY_STATUS_CHARGING; 723 status = POWER_SUPPLY_STATUS_CHARGING;
@@ -706,6 +727,7 @@ static int hidpp20_batterylevel_map_status_capacity(u8 data[3], int *capacity,
706 break; 727 break;
707 case 3: /* charge complete */ 728 case 3: /* charge complete */
708 status = POWER_SUPPLY_STATUS_FULL; 729 status = POWER_SUPPLY_STATUS_FULL;
730 *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
709 *capacity = 100; 731 *capacity = 100;
710 break; 732 break;
711 case 4: /* recharging below optimal speed */ 733 case 4: /* recharging below optimal speed */
@@ -726,7 +748,8 @@ static int hidpp20_batterylevel_get_battery_capacity(struct hidpp_device *hidpp,
726 u8 feature_index, 748 u8 feature_index,
727 int *status, 749 int *status,
728 int *capacity, 750 int *capacity,
729 int *next_capacity) 751 int *next_capacity,
752 int *level)
730{ 753{
731 struct hidpp_report response; 754 struct hidpp_report response;
732 int ret; 755 int ret;
@@ -744,7 +767,38 @@ static int hidpp20_batterylevel_get_battery_capacity(struct hidpp_device *hidpp,
744 return ret; 767 return ret;
745 768
746 *status = hidpp20_batterylevel_map_status_capacity(params, capacity, 769 *status = hidpp20_batterylevel_map_status_capacity(params, capacity,
747 next_capacity); 770 next_capacity,
771 level);
772
773 return 0;
774}
775
776static int hidpp20_batterylevel_get_battery_info(struct hidpp_device *hidpp,
777 u8 feature_index)
778{
779 struct hidpp_report response;
780 int ret;
781 u8 *params = (u8 *)response.fap.params;
782 unsigned int level_count, flags;
783
784 ret = hidpp_send_fap_command_sync(hidpp, feature_index,
785 CMD_BATTERY_LEVEL_STATUS_GET_BATTERY_CAPABILITY,
786 NULL, 0, &response);
787 if (ret > 0) {
788 hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
789 __func__, ret);
790 return -EPROTO;
791 }
792 if (ret)
793 return ret;
794
795 level_count = params[0];
796 flags = params[1];
797
798 if (level_count < 10 || !(flags & FLAG_BATTERY_LEVEL_MILEAGE))
799 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS;
800 else
801 hidpp->capabilities |= HIDPP_CAPABILITY_BATTERY_MILEAGE;
748 802
749 return 0; 803 return 0;
750} 804}
@@ -753,7 +807,7 @@ static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
753{ 807{
754 u8 feature_type; 808 u8 feature_type;
755 int ret; 809 int ret;
756 int status, capacity, next_capacity; 810 int status, capacity, next_capacity, level;
757 811
758 if (hidpp->battery.feature_index == 0) { 812 if (hidpp->battery.feature_index == 0) {
759 ret = hidpp_root_get_feature(hidpp, 813 ret = hidpp_root_get_feature(hidpp,
@@ -767,12 +821,18 @@ static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
767 ret = hidpp20_batterylevel_get_battery_capacity(hidpp, 821 ret = hidpp20_batterylevel_get_battery_capacity(hidpp,
768 hidpp->battery.feature_index, 822 hidpp->battery.feature_index,
769 &status, &capacity, 823 &status, &capacity,
770 &next_capacity); 824 &next_capacity, &level);
825 if (ret)
826 return ret;
827
828 ret = hidpp20_batterylevel_get_battery_info(hidpp,
829 hidpp->battery.feature_index);
771 if (ret) 830 if (ret)
772 return ret; 831 return ret;
773 832
774 hidpp->battery.status = status; 833 hidpp->battery.status = status;
775 hidpp->battery.capacity = capacity; 834 hidpp->battery.capacity = capacity;
835 hidpp->battery.level = level;
776 /* the capacity is only available when discharging or full */ 836 /* the capacity is only available when discharging or full */
777 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING || 837 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
778 status == POWER_SUPPLY_STATUS_FULL; 838 status == POWER_SUPPLY_STATUS_FULL;
@@ -784,7 +844,7 @@ static int hidpp20_battery_event(struct hidpp_device *hidpp,
784 u8 *data, int size) 844 u8 *data, int size)
785{ 845{
786 struct hidpp_report *report = (struct hidpp_report *)data; 846 struct hidpp_report *report = (struct hidpp_report *)data;
787 int status, capacity, next_capacity; 847 int status, capacity, next_capacity, level;
788 bool changed; 848 bool changed;
789 849
790 if (report->fap.feature_index != hidpp->battery.feature_index || 850 if (report->fap.feature_index != hidpp->battery.feature_index ||
@@ -793,16 +853,19 @@ static int hidpp20_battery_event(struct hidpp_device *hidpp,
793 853
794 status = hidpp20_batterylevel_map_status_capacity(report->fap.params, 854 status = hidpp20_batterylevel_map_status_capacity(report->fap.params,
795 &capacity, 855 &capacity,
796 &next_capacity); 856 &next_capacity,
857 &level);
797 858
798 /* the capacity is only available when discharging or full */ 859 /* the capacity is only available when discharging or full */
799 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING || 860 hidpp->battery.online = status == POWER_SUPPLY_STATUS_DISCHARGING ||
800 status == POWER_SUPPLY_STATUS_FULL; 861 status == POWER_SUPPLY_STATUS_FULL;
801 862
802 changed = capacity != hidpp->battery.capacity || 863 changed = capacity != hidpp->battery.capacity ||
864 level != hidpp->battery.level ||
803 status != hidpp->battery.status; 865 status != hidpp->battery.status;
804 866
805 if (changed) { 867 if (changed) {
868 hidpp->battery.level = level;
806 hidpp->battery.capacity = capacity; 869 hidpp->battery.capacity = capacity;
807 hidpp->battery.status = status; 870 hidpp->battery.status = status;
808 if (hidpp->battery.ps) 871 if (hidpp->battery.ps)
@@ -815,11 +878,12 @@ static int hidpp20_battery_event(struct hidpp_device *hidpp,
815static enum power_supply_property hidpp_battery_props[] = { 878static enum power_supply_property hidpp_battery_props[] = {
816 POWER_SUPPLY_PROP_ONLINE, 879 POWER_SUPPLY_PROP_ONLINE,
817 POWER_SUPPLY_PROP_STATUS, 880 POWER_SUPPLY_PROP_STATUS,
818 POWER_SUPPLY_PROP_CAPACITY,
819 POWER_SUPPLY_PROP_SCOPE, 881 POWER_SUPPLY_PROP_SCOPE,
820 POWER_SUPPLY_PROP_MODEL_NAME, 882 POWER_SUPPLY_PROP_MODEL_NAME,
821 POWER_SUPPLY_PROP_MANUFACTURER, 883 POWER_SUPPLY_PROP_MANUFACTURER,
822 POWER_SUPPLY_PROP_SERIAL_NUMBER, 884 POWER_SUPPLY_PROP_SERIAL_NUMBER,
885 0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY, */
886 0, /* placeholder for POWER_SUPPLY_PROP_CAPACITY_LEVEL, */
823}; 887};
824 888
825static int hidpp_battery_get_property(struct power_supply *psy, 889static int hidpp_battery_get_property(struct power_supply *psy,
@@ -836,6 +900,9 @@ static int hidpp_battery_get_property(struct power_supply *psy,
836 case POWER_SUPPLY_PROP_CAPACITY: 900 case POWER_SUPPLY_PROP_CAPACITY:
837 val->intval = hidpp->battery.capacity; 901 val->intval = hidpp->battery.capacity;
838 break; 902 break;
903 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
904 val->intval = hidpp->battery.level;
905 break;
839 case POWER_SUPPLY_PROP_SCOPE: 906 case POWER_SUPPLY_PROP_SCOPE:
840 val->intval = POWER_SUPPLY_SCOPE_DEVICE; 907 val->intval = POWER_SUPPLY_SCOPE_DEVICE;
841 break; 908 break;
@@ -2316,7 +2383,9 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
2316 static atomic_t battery_no = ATOMIC_INIT(0); 2383 static atomic_t battery_no = ATOMIC_INIT(0);
2317 struct power_supply_config cfg = { .drv_data = hidpp }; 2384 struct power_supply_config cfg = { .drv_data = hidpp };
2318 struct power_supply_desc *desc = &hidpp->battery.desc; 2385 struct power_supply_desc *desc = &hidpp->battery.desc;
2386 enum power_supply_property *battery_props;
2319 struct hidpp_battery *battery; 2387 struct hidpp_battery *battery;
2388 unsigned int num_battery_props;
2320 unsigned long n; 2389 unsigned long n;
2321 int ret; 2390 int ret;
2322 2391
@@ -2332,11 +2401,25 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
2332 return -ENOENT; 2401 return -ENOENT;
2333 } 2402 }
2334 2403
2404 battery_props = devm_kmemdup(&hidpp->hid_dev->dev,
2405 hidpp_battery_props,
2406 sizeof(hidpp_battery_props),
2407 GFP_KERNEL);
2408 num_battery_props = ARRAY_SIZE(hidpp_battery_props) - 2;
2409
2410 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE)
2411 battery_props[num_battery_props++] =
2412 POWER_SUPPLY_PROP_CAPACITY;
2413
2414 if (hidpp->capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS)
2415 battery_props[num_battery_props++] =
2416 POWER_SUPPLY_PROP_CAPACITY_LEVEL;
2417
2335 battery = &hidpp->battery; 2418 battery = &hidpp->battery;
2336 2419
2337 n = atomic_inc_return(&battery_no) - 1; 2420 n = atomic_inc_return(&battery_no) - 1;
2338 desc->properties = hidpp_battery_props; 2421 desc->properties = battery_props;
2339 desc->num_properties = ARRAY_SIZE(hidpp_battery_props); 2422 desc->num_properties = num_battery_props;
2340 desc->get_property = hidpp_battery_get_property; 2423 desc->get_property = hidpp_battery_get_property;
2341 sprintf(battery->name, "hidpp_battery_%ld", n); 2424 sprintf(battery->name, "hidpp_battery_%ld", n);
2342 desc->name = battery->name; 2425 desc->name = battery->name;
@@ -2424,6 +2507,7 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
2424 if (hidpp->battery.ps) { 2507 if (hidpp->battery.ps) {
2425 hidpp->battery.online = false; 2508 hidpp->battery.online = false;
2426 hidpp->battery.status = POWER_SUPPLY_STATUS_UNKNOWN; 2509 hidpp->battery.status = POWER_SUPPLY_STATUS_UNKNOWN;
2510 hidpp->battery.level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
2427 power_supply_changed(hidpp->battery.ps); 2511 power_supply_changed(hidpp->battery.ps);
2428 } 2512 }
2429 return; 2513 return;