@@ -94,6 +94,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
9494#define HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL BIT(7)
9595#define HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL BIT(8)
9696#define HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL BIT(9)
97+ #define HIDPP_CAPABILITY_ADC_MEASUREMENT BIT(10)
9798
9899#define lg_map_key_clear (c ) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
99100
@@ -145,6 +146,7 @@ struct hidpp_battery {
145146 u8 feature_index ;
146147 u8 solar_feature_index ;
147148 u8 voltage_feature_index ;
149+ u8 adc_measurement_feature_index ;
148150 struct power_supply_desc desc ;
149151 struct power_supply * ps ;
150152 char name [64 ];
@@ -1790,6 +1792,162 @@ static int hidpp_set_wireless_feature_index(struct hidpp_device *hidpp)
17901792 return ret ;
17911793}
17921794
1795+ /* -------------------------------------------------------------------------- */
1796+ /* 0x1f20: ADC measurement */
1797+ /* -------------------------------------------------------------------------- */
1798+
1799+ #define HIDPP_PAGE_ADC_MEASUREMENT 0x1f20
1800+
1801+ #define CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT 0x00
1802+
1803+ #define EVENT_ADC_MEASUREMENT_STATUS_BROADCAST 0x00
1804+
1805+ static int hidpp20_map_adc_measurement_1f20_capacity (struct hid_device * hid_dev , int voltage )
1806+ {
1807+ /* NB: This voltage curve doesn't necessarily map perfectly to all
1808+ * devices that implement the ADC_MEASUREMENT feature. This is because
1809+ * there are a few devices that use different battery technology.
1810+ *
1811+ * Adapted from:
1812+ * https://github.com/Sapd/HeadsetControl/blob/acd972be0468e039b93aae81221f20a54d2d60f7/src/devices/logitech_g633_g933_935.c#L44-L52
1813+ */
1814+ static const int voltages [100 ] = {
1815+ 4030 , 4024 , 4018 , 4011 , 4003 , 3994 , 3985 , 3975 , 3963 , 3951 ,
1816+ 3937 , 3922 , 3907 , 3893 , 3880 , 3868 , 3857 , 3846 , 3837 , 3828 ,
1817+ 3820 , 3812 , 3805 , 3798 , 3791 , 3785 , 3779 , 3773 , 3768 , 3762 ,
1818+ 3757 , 3752 , 3747 , 3742 , 3738 , 3733 , 3729 , 3724 , 3720 , 3716 ,
1819+ 3712 , 3708 , 3704 , 3700 , 3696 , 3692 , 3688 , 3685 , 3681 , 3677 ,
1820+ 3674 , 3670 , 3667 , 3663 , 3660 , 3657 , 3653 , 3650 , 3646 , 3643 ,
1821+ 3640 , 3637 , 3633 , 3630 , 3627 , 3624 , 3620 , 3617 , 3614 , 3611 ,
1822+ 3608 , 3604 , 3601 , 3598 , 3595 , 3592 , 3589 , 3585 , 3582 , 3579 ,
1823+ 3576 , 3573 , 3569 , 3566 , 3563 , 3560 , 3556 , 3553 , 3550 , 3546 ,
1824+ 3543 , 3539 , 3536 , 3532 , 3529 , 3525 , 3499 , 3466 , 3433 , 3399 ,
1825+ };
1826+
1827+ int i ;
1828+
1829+ if (voltage == 0 )
1830+ return 0 ;
1831+
1832+ if (unlikely (voltage < 3400 || voltage >= 5000 ))
1833+ hid_warn_once (hid_dev ,
1834+ "%s: possibly using the wrong voltage curve\n" ,
1835+ __func__ );
1836+
1837+ for (i = 0 ; i < ARRAY_SIZE (voltages ); i ++ ) {
1838+ if (voltage >= voltages [i ])
1839+ return ARRAY_SIZE (voltages ) - i ;
1840+ }
1841+
1842+ return 0 ;
1843+ }
1844+
1845+ static int hidpp20_map_adc_measurement_1f20 (u8 data [3 ], int * voltage )
1846+ {
1847+ int status ;
1848+ u8 flags ;
1849+
1850+ flags = data [2 ];
1851+
1852+ switch (flags ) {
1853+ case 0x01 :
1854+ status = POWER_SUPPLY_STATUS_DISCHARGING ;
1855+ break ;
1856+ case 0x03 :
1857+ status = POWER_SUPPLY_STATUS_CHARGING ;
1858+ break ;
1859+ case 0x07 :
1860+ status = POWER_SUPPLY_STATUS_FULL ;
1861+ break ;
1862+ case 0x0F :
1863+ default :
1864+ status = POWER_SUPPLY_STATUS_UNKNOWN ;
1865+ break ;
1866+ }
1867+
1868+ * voltage = get_unaligned_be16 (data );
1869+
1870+ dbg_hid ("Parsed 1f20 data as flag 0x%02x voltage %dmV\n" ,
1871+ flags , * voltage );
1872+
1873+ return status ;
1874+ }
1875+
1876+ /* Return value is whether the device is online */
1877+ static bool hidpp20_get_adc_measurement_1f20 (struct hidpp_device * hidpp ,
1878+ u8 feature_index ,
1879+ int * status , int * voltage )
1880+ {
1881+ struct hidpp_report response ;
1882+ int ret ;
1883+ u8 * params = (u8 * )response .fap .params ;
1884+
1885+ * status = POWER_SUPPLY_STATUS_UNKNOWN ;
1886+ * voltage = 0 ;
1887+ ret = hidpp_send_fap_command_sync (hidpp , feature_index ,
1888+ CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT ,
1889+ NULL , 0 , & response );
1890+
1891+ if (ret > 0 ) {
1892+ hid_dbg (hidpp -> hid_dev , "%s: received protocol error 0x%02x\n" ,
1893+ __func__ , ret );
1894+ return false;
1895+ }
1896+
1897+ * status = hidpp20_map_adc_measurement_1f20 (params , voltage );
1898+ return true;
1899+ }
1900+
1901+ static int hidpp20_query_adc_measurement_info_1f20 (struct hidpp_device * hidpp )
1902+ {
1903+ u8 feature_type ;
1904+
1905+ if (hidpp -> battery .adc_measurement_feature_index == 0xff ) {
1906+ int ret ;
1907+
1908+ ret = hidpp_root_get_feature (hidpp , HIDPP_PAGE_ADC_MEASUREMENT ,
1909+ & hidpp -> battery .adc_measurement_feature_index ,
1910+ & feature_type );
1911+ if (ret )
1912+ return ret ;
1913+
1914+ hidpp -> capabilities |= HIDPP_CAPABILITY_ADC_MEASUREMENT ;
1915+ }
1916+
1917+ hidpp -> battery .online = hidpp20_get_adc_measurement_1f20 (hidpp ,
1918+ hidpp -> battery .adc_measurement_feature_index ,
1919+ & hidpp -> battery .status ,
1920+ & hidpp -> battery .voltage );
1921+ hidpp -> battery .capacity = hidpp20_map_adc_measurement_1f20_capacity (hidpp -> hid_dev ,
1922+ hidpp -> battery .voltage );
1923+
1924+ return 0 ;
1925+ }
1926+
1927+ static int hidpp20_adc_measurement_event_1f20 (struct hidpp_device * hidpp ,
1928+ u8 * data , int size )
1929+ {
1930+ struct hidpp_report * report = (struct hidpp_report * )data ;
1931+ int status , voltage ;
1932+
1933+ if (report -> fap .feature_index != hidpp -> battery .adc_measurement_feature_index ||
1934+ report -> fap .funcindex_clientid != EVENT_ADC_MEASUREMENT_STATUS_BROADCAST )
1935+ return 0 ;
1936+
1937+ status = hidpp20_map_adc_measurement_1f20 (report -> fap .params , & voltage );
1938+
1939+ hidpp -> battery .online = status != POWER_SUPPLY_STATUS_UNKNOWN ;
1940+
1941+ if (voltage != hidpp -> battery .voltage || status != hidpp -> battery .status ) {
1942+ hidpp -> battery .status = status ;
1943+ hidpp -> battery .voltage = voltage ;
1944+ hidpp -> battery .capacity = hidpp20_map_adc_measurement_1f20_capacity (hidpp -> hid_dev , voltage );
1945+ if (hidpp -> battery .ps )
1946+ power_supply_changed (hidpp -> battery .ps );
1947+ }
1948+ return 0 ;
1949+ }
1950+
17931951/* -------------------------------------------------------------------------- */
17941952/* 0x2120: Hi-resolution scrolling */
17951953/* -------------------------------------------------------------------------- */
@@ -3708,6 +3866,9 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
37083866 ret = hidpp20_battery_voltage_event (hidpp , data , size );
37093867 if (ret != 0 )
37103868 return ret ;
3869+ ret = hidpp20_adc_measurement_event_1f20 (hidpp , data , size );
3870+ if (ret != 0 )
3871+ return ret ;
37113872 }
37123873
37133874 if (hidpp -> capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY ) {
@@ -3831,6 +3992,7 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
38313992 hidpp -> battery .feature_index = 0xff ;
38323993 hidpp -> battery .solar_feature_index = 0xff ;
38333994 hidpp -> battery .voltage_feature_index = 0xff ;
3995+ hidpp -> battery .adc_measurement_feature_index = 0xff ;
38343996
38353997 if (hidpp -> protocol_major >= 2 ) {
38363998 if (hidpp -> quirks & HIDPP_QUIRK_CLASS_K750 )
@@ -3844,6 +4006,8 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
38444006 ret = hidpp20_query_battery_info_1004 (hidpp );
38454007 if (ret )
38464008 ret = hidpp20_query_battery_voltage_info (hidpp );
4009+ if (ret )
4010+ ret = hidpp20_query_adc_measurement_info_1f20 (hidpp );
38474011 }
38484012
38494013 if (ret )
@@ -3873,15 +4037,17 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
38734037
38744038 if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
38754039 hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE ||
3876- hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
4040+ hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE ||
4041+ hidpp -> capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT )
38774042 battery_props [num_battery_props ++ ] =
38784043 POWER_SUPPLY_PROP_CAPACITY ;
38794044
38804045 if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS )
38814046 battery_props [num_battery_props ++ ] =
38824047 POWER_SUPPLY_PROP_CAPACITY_LEVEL ;
38834048
3884- if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
4049+ if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE ||
4050+ hidpp -> capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT )
38854051 battery_props [num_battery_props ++ ] =
38864052 POWER_SUPPLY_PROP_VOLTAGE_NOW ;
38874053
@@ -4054,6 +4220,8 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
40544220 hidpp20_query_battery_voltage_info (hidpp );
40554221 else if (hidpp -> capabilities & HIDPP_CAPABILITY_UNIFIED_BATTERY )
40564222 hidpp20_query_battery_info_1004 (hidpp );
4223+ else if (hidpp -> capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT )
4224+ hidpp20_query_adc_measurement_info_1f20 (hidpp );
40574225 else
40584226 hidpp20_query_battery_info_1000 (hidpp );
40594227 }
0 commit comments