@@ -92,6 +92,8 @@ MODULE_PARM_DESC(disable_tap_to_click,
9292#define HIDPP_CAPABILITY_BATTERY_MILEAGE BIT(2)
9393#define HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS BIT(3)
9494#define HIDPP_CAPABILITY_BATTERY_VOLTAGE BIT(4)
95+ #define HIDPP_CAPABILITY_BATTERY_PERCENTAGE BIT(5)
96+ #define HIDPP_CAPABILITY_UNIFIED_BATTERY BIT(6)
9597
9698#define lg_map_key_clear (c ) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
9799
@@ -152,6 +154,7 @@ struct hidpp_battery {
152154 int voltage ;
153155 int charge_type ;
154156 bool online ;
157+ u8 supported_levels_1004 ;
155158};
156159
157160/**
@@ -1171,7 +1174,7 @@ static int hidpp20_batterylevel_get_battery_info(struct hidpp_device *hidpp,
11711174 return 0 ;
11721175}
11731176
1174- static int hidpp20_query_battery_info (struct hidpp_device * hidpp )
1177+ static int hidpp20_query_battery_info_1000 (struct hidpp_device * hidpp )
11751178{
11761179 u8 feature_type ;
11771180 int ret ;
@@ -1208,7 +1211,7 @@ static int hidpp20_query_battery_info(struct hidpp_device *hidpp)
12081211 return 0 ;
12091212}
12101213
1211- static int hidpp20_battery_event (struct hidpp_device * hidpp ,
1214+ static int hidpp20_battery_event_1000 (struct hidpp_device * hidpp ,
12121215 u8 * data , int size )
12131216{
12141217 struct hidpp_report * report = (struct hidpp_report * )data ;
@@ -1380,6 +1383,224 @@ static int hidpp20_battery_voltage_event(struct hidpp_device *hidpp,
13801383 return 0 ;
13811384}
13821385
1386+ /* -------------------------------------------------------------------------- */
1387+ /* 0x1004: Unified battery */
1388+ /* -------------------------------------------------------------------------- */
1389+
1390+ #define HIDPP_PAGE_UNIFIED_BATTERY 0x1004
1391+
1392+ #define CMD_UNIFIED_BATTERY_GET_CAPABILITIES 0x00
1393+ #define CMD_UNIFIED_BATTERY_GET_STATUS 0x10
1394+
1395+ #define EVENT_UNIFIED_BATTERY_STATUS_EVENT 0x00
1396+
1397+ #define FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL BIT(0)
1398+ #define FLAG_UNIFIED_BATTERY_LEVEL_LOW BIT(1)
1399+ #define FLAG_UNIFIED_BATTERY_LEVEL_GOOD BIT(2)
1400+ #define FLAG_UNIFIED_BATTERY_LEVEL_FULL BIT(3)
1401+
1402+ #define FLAG_UNIFIED_BATTERY_FLAGS_RECHARGEABLE BIT(0)
1403+ #define FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE BIT(1)
1404+
1405+ static int hidpp20_unifiedbattery_get_capabilities (struct hidpp_device * hidpp ,
1406+ u8 feature_index )
1407+ {
1408+ struct hidpp_report response ;
1409+ int ret ;
1410+ u8 * params = (u8 * )response .fap .params ;
1411+
1412+ if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS ||
1413+ hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE ) {
1414+ /* we have already set the device capabilities, so let's skip */
1415+ return 0 ;
1416+ }
1417+
1418+ ret = hidpp_send_fap_command_sync (hidpp , feature_index ,
1419+ CMD_UNIFIED_BATTERY_GET_CAPABILITIES ,
1420+ NULL , 0 , & response );
1421+ /* Ignore these intermittent errors */
1422+ if (ret == HIDPP_ERROR_RESOURCE_ERROR )
1423+ return - EIO ;
1424+ if (ret > 0 ) {
1425+ hid_err (hidpp -> hid_dev , "%s: received protocol error 0x%02x\n" ,
1426+ __func__ , ret );
1427+ return - EPROTO ;
1428+ }
1429+ if (ret )
1430+ return ret ;
1431+
1432+ /*
1433+ * If the device supports state of charge (battery percentage) we won't
1434+ * export the battery level information. there are 4 possible battery
1435+ * levels and they all are optional, this means that the device might
1436+ * not support any of them, we are just better off with the battery
1437+ * percentage.
1438+ */
1439+ if (params [1 ] & FLAG_UNIFIED_BATTERY_FLAGS_STATE_OF_CHARGE ) {
1440+ hidpp -> capabilities |= HIDPP_CAPABILITY_BATTERY_PERCENTAGE ;
1441+ hidpp -> battery .supported_levels_1004 = 0 ;
1442+ } else {
1443+ hidpp -> capabilities |= HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS ;
1444+ hidpp -> battery .supported_levels_1004 = params [0 ];
1445+ }
1446+
1447+ return 0 ;
1448+ }
1449+
1450+ static int hidpp20_unifiedbattery_map_status (struct hidpp_device * hidpp ,
1451+ u8 charging_status ,
1452+ u8 external_power_status )
1453+ {
1454+ int status ;
1455+
1456+ switch (charging_status ) {
1457+ case 0 : /* discharging */
1458+ status = POWER_SUPPLY_STATUS_DISCHARGING ;
1459+ break ;
1460+ case 1 : /* charging */
1461+ case 2 : /* charging slow */
1462+ status = POWER_SUPPLY_STATUS_CHARGING ;
1463+ break ;
1464+ case 3 : /* complete */
1465+ status = POWER_SUPPLY_STATUS_FULL ;
1466+ break ;
1467+ case 4 : /* error */
1468+ status = POWER_SUPPLY_STATUS_NOT_CHARGING ;
1469+ hid_info (hidpp -> hid_dev , "%s: charging error" ,
1470+ hidpp -> name );
1471+ break ;
1472+ default :
1473+ status = POWER_SUPPLY_STATUS_NOT_CHARGING ;
1474+ break ;
1475+ }
1476+
1477+ return status ;
1478+ }
1479+
1480+ static int hidpp20_unifiedbattery_map_level (struct hidpp_device * hidpp ,
1481+ u8 battery_level )
1482+ {
1483+ /* cler unsupported level bits */
1484+ battery_level &= hidpp -> battery .supported_levels_1004 ;
1485+
1486+ if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_FULL )
1487+ return POWER_SUPPLY_CAPACITY_LEVEL_FULL ;
1488+ else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_GOOD )
1489+ return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL ;
1490+ else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_LOW )
1491+ return POWER_SUPPLY_CAPACITY_LEVEL_LOW ;
1492+ else if (battery_level & FLAG_UNIFIED_BATTERY_LEVEL_CRITICAL )
1493+ return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL ;
1494+
1495+ return POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN ;
1496+ }
1497+
1498+ static int hidpp20_unifiedbattery_get_status (struct hidpp_device * hidpp ,
1499+ u8 feature_index ,
1500+ u8 * state_of_charge ,
1501+ int * status ,
1502+ int * level )
1503+ {
1504+ struct hidpp_report response ;
1505+ int ret ;
1506+ u8 * params = (u8 * )response .fap .params ;
1507+
1508+ ret = hidpp_send_fap_command_sync (hidpp , feature_index ,
1509+ CMD_UNIFIED_BATTERY_GET_STATUS ,
1510+ NULL , 0 , & response );
1511+ /* Ignore these intermittent errors */
1512+ if (ret == HIDPP_ERROR_RESOURCE_ERROR )
1513+ return - EIO ;
1514+ if (ret > 0 ) {
1515+ hid_err (hidpp -> hid_dev , "%s: received protocol error 0x%02x\n" ,
1516+ __func__ , ret );
1517+ return - EPROTO ;
1518+ }
1519+ if (ret )
1520+ return ret ;
1521+
1522+ * state_of_charge = params [0 ];
1523+ * status = hidpp20_unifiedbattery_map_status (hidpp , params [2 ], params [3 ]);
1524+ * level = hidpp20_unifiedbattery_map_level (hidpp , params [1 ]);
1525+
1526+ return 0 ;
1527+ }
1528+
1529+ static int hidpp20_query_battery_info_1004 (struct hidpp_device * hidpp )
1530+ {
1531+ u8 feature_type ;
1532+ int ret ;
1533+ u8 state_of_charge ;
1534+ int status , level ;
1535+
1536+ if (hidpp -> battery .feature_index == 0xff ) {
1537+ ret = hidpp_root_get_feature (hidpp ,
1538+ HIDPP_PAGE_UNIFIED_BATTERY ,
1539+ & hidpp -> battery .feature_index ,
1540+ & feature_type );
1541+ if (ret )
1542+ return ret ;
1543+ }
1544+
1545+ ret = hidpp20_unifiedbattery_get_capabilities (hidpp ,
1546+ hidpp -> battery .feature_index );
1547+ if (ret )
1548+ return ret ;
1549+
1550+ ret = hidpp20_unifiedbattery_get_status (hidpp ,
1551+ hidpp -> battery .feature_index ,
1552+ & state_of_charge ,
1553+ & status ,
1554+ & level );
1555+ if (ret )
1556+ return ret ;
1557+
1558+ hidpp -> capabilities |= HIDPP_CAPABILITY_UNIFIED_BATTERY ;
1559+ hidpp -> battery .capacity = state_of_charge ;
1560+ hidpp -> battery .status = status ;
1561+ hidpp -> battery .level = level ;
1562+ hidpp -> battery .online = true;
1563+
1564+ return 0 ;
1565+ }
1566+
1567+ static int hidpp20_battery_event_1004 (struct hidpp_device * hidpp ,
1568+ u8 * data , int size )
1569+ {
1570+ struct hidpp_report * report = (struct hidpp_report * )data ;
1571+ u8 * params = (u8 * )report -> fap .params ;
1572+ int state_of_charge , status , level ;
1573+ bool changed ;
1574+
1575+ if (report -> fap .feature_index != hidpp -> battery .feature_index ||
1576+ report -> fap .funcindex_clientid != EVENT_UNIFIED_BATTERY_STATUS_EVENT )
1577+ return 0 ;
1578+
1579+ state_of_charge = params [0 ];
1580+ status = hidpp20_unifiedbattery_map_status (hidpp , params [2 ], params [3 ]);
1581+ level = hidpp20_unifiedbattery_map_level (hidpp , params [1 ]);
1582+
1583+ changed = status != hidpp -> battery .status ||
1584+ (state_of_charge != hidpp -> battery .capacity &&
1585+ hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE ) ||
1586+ (level != hidpp -> battery .level &&
1587+ hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS );
1588+
1589+ if (changed ) {
1590+ hidpp -> battery .capacity = state_of_charge ;
1591+ hidpp -> battery .status = status ;
1592+ hidpp -> battery .level = level ;
1593+ if (hidpp -> battery .ps )
1594+ power_supply_changed (hidpp -> battery .ps );
1595+ }
1596+
1597+ return 0 ;
1598+ }
1599+
1600+ /* -------------------------------------------------------------------------- */
1601+ /* Battery feature helpers */
1602+ /* -------------------------------------------------------------------------- */
1603+
13831604static enum power_supply_property hidpp_battery_props [] = {
13841605 POWER_SUPPLY_PROP_ONLINE ,
13851606 POWER_SUPPLY_PROP_STATUS ,
@@ -3307,7 +3528,10 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
33073528 }
33083529
33093530 if (hidpp -> capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY ) {
3310- ret = hidpp20_battery_event (hidpp , data , size );
3531+ ret = hidpp20_battery_event_1000 (hidpp , data , size );
3532+ if (ret != 0 )
3533+ return ret ;
3534+ ret = hidpp20_battery_event_1004 (hidpp , data , size );
33113535 if (ret != 0 )
33123536 return ret ;
33133537 ret = hidpp_solar_battery_event (hidpp , data , size );
@@ -3443,9 +3667,14 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
34433667 if (hidpp -> quirks & HIDPP_QUIRK_CLASS_K750 )
34443668 ret = hidpp_solar_request_battery_event (hidpp );
34453669 else {
3446- ret = hidpp20_query_battery_voltage_info (hidpp );
3670+ /* we only support one battery feature right now, so let's
3671+ first check the ones that support battery level first
3672+ and leave voltage for last */
3673+ ret = hidpp20_query_battery_info_1000 (hidpp );
3674+ if (ret )
3675+ ret = hidpp20_query_battery_info_1004 (hidpp );
34473676 if (ret )
3448- ret = hidpp20_query_battery_info (hidpp );
3677+ ret = hidpp20_query_battery_voltage_info (hidpp );
34493678 }
34503679
34513680 if (ret )
@@ -3473,7 +3702,8 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
34733702
34743703 num_battery_props = ARRAY_SIZE (hidpp_battery_props ) - 3 ;
34753704
3476- if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE )
3705+ if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
3706+ hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE )
34773707 battery_props [num_battery_props ++ ] =
34783708 POWER_SUPPLY_PROP_CAPACITY ;
34793709
@@ -3650,8 +3880,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
36503880 } else if (hidpp -> capabilities & HIDPP_CAPABILITY_HIDPP20_BATTERY ) {
36513881 if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
36523882 hidpp20_query_battery_voltage_info (hidpp );
3883+ else if (hidpp -> capabilities & HIDPP_CAPABILITY_UNIFIED_BATTERY )
3884+ hidpp20_query_battery_info_1004 (hidpp );
36533885 else
3654- hidpp20_query_battery_info (hidpp );
3886+ hidpp20_query_battery_info_1000 (hidpp );
36553887 }
36563888 if (hidpp -> battery .ps )
36573889 power_supply_changed (hidpp -> battery .ps );
0 commit comments