@@ -74,6 +74,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
7474#define HIDPP_QUIRK_HIDPP_EXTRA_MOUSE_BTNS BIT(27)
7575#define HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS BIT(28)
7676#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(29)
77+ #define HIDPP_QUIRK_WIRELESS_STATUS BIT(30)
7778
7879/* These are just aliases for now */
7980#define HIDPP_QUIRK_KBD_SCROLL_WHEEL HIDPP_QUIRK_HIDPP_WHEELS
@@ -94,6 +95,7 @@ MODULE_PARM_DESC(disable_tap_to_click,
9495#define HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL BIT(7)
9596#define HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL BIT(8)
9697#define HIDPP_CAPABILITY_HIDPP10_FAST_SCROLL BIT(9)
98+ #define HIDPP_CAPABILITY_ADC_MEASUREMENT BIT(10)
9799
98100#define lg_map_key_clear (c ) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
99101
@@ -145,6 +147,7 @@ struct hidpp_battery {
145147 u8 feature_index ;
146148 u8 solar_feature_index ;
147149 u8 voltage_feature_index ;
150+ u8 adc_measurement_feature_index ;
148151 struct power_supply_desc desc ;
149152 struct power_supply * ps ;
150153 char name [64 ];
@@ -471,6 +474,26 @@ static void hidpp_prefix_name(char **name, int name_length)
471474 * name = new_name ;
472475}
473476
477+ /*
478+ * Updates the USB wireless_status based on whether the headset
479+ * is turned on and reachable.
480+ */
481+ static void hidpp_update_usb_wireless_status (struct hidpp_device * hidpp )
482+ {
483+ struct hid_device * hdev = hidpp -> hid_dev ;
484+ struct usb_interface * intf ;
485+
486+ if (!(hidpp -> quirks & HIDPP_QUIRK_WIRELESS_STATUS ))
487+ return ;
488+ if (!hid_is_usb (hdev ))
489+ return ;
490+
491+ intf = to_usb_interface (hdev -> dev .parent );
492+ usb_set_wireless_status (intf , hidpp -> battery .online ?
493+ USB_WIRELESS_STATUS_CONNECTED :
494+ USB_WIRELESS_STATUS_DISCONNECTED );
495+ }
496+
474497/**
475498 * hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll
476499 * events given a high-resolution wheel
@@ -853,8 +876,7 @@ static int hidpp_unifying_init(struct hidpp_device *hidpp)
853876 if (ret )
854877 return ret ;
855878
856- snprintf (hdev -> uniq , sizeof (hdev -> uniq ), "%04x-%4phD" ,
857- hdev -> product , & serial );
879+ snprintf (hdev -> uniq , sizeof (hdev -> uniq ), "%4phD" , & serial );
858880 dbg_hid ("HID++ Unifying: Got serial: %s\n" , hdev -> uniq );
859881
860882 name = hidpp_unifying_get_name (hidpp );
@@ -947,6 +969,54 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
947969 return 0 ;
948970}
949971
972+ /* -------------------------------------------------------------------------- */
973+ /* 0x0003: Device Information */
974+ /* -------------------------------------------------------------------------- */
975+
976+ #define HIDPP_PAGE_DEVICE_INFORMATION 0x0003
977+
978+ #define CMD_GET_DEVICE_INFO 0x00
979+
980+ static int hidpp_get_serial (struct hidpp_device * hidpp , u32 * serial )
981+ {
982+ struct hidpp_report response ;
983+ u8 feature_type ;
984+ u8 feature_index ;
985+ int ret ;
986+
987+ ret = hidpp_root_get_feature (hidpp , HIDPP_PAGE_DEVICE_INFORMATION ,
988+ & feature_index ,
989+ & feature_type );
990+ if (ret )
991+ return ret ;
992+
993+ ret = hidpp_send_fap_command_sync (hidpp , feature_index ,
994+ CMD_GET_DEVICE_INFO ,
995+ NULL , 0 , & response );
996+ if (ret )
997+ return ret ;
998+
999+ /* See hidpp_unifying_get_serial() */
1000+ * serial = * ((u32 * )& response .rap .params [1 ]);
1001+ return 0 ;
1002+ }
1003+
1004+ static int hidpp_serial_init (struct hidpp_device * hidpp )
1005+ {
1006+ struct hid_device * hdev = hidpp -> hid_dev ;
1007+ u32 serial ;
1008+ int ret ;
1009+
1010+ ret = hidpp_get_serial (hidpp , & serial );
1011+ if (ret )
1012+ return ret ;
1013+
1014+ snprintf (hdev -> uniq , sizeof (hdev -> uniq ), "%4phD" , & serial );
1015+ dbg_hid ("HID++ DeviceInformation: Got serial: %s\n" , hdev -> uniq );
1016+
1017+ return 0 ;
1018+ }
1019+
9501020/* -------------------------------------------------------------------------- */
9511021/* 0x0005: GetDeviceNameType */
9521022/* -------------------------------------------------------------------------- */
@@ -1357,7 +1427,7 @@ static int hidpp20_map_battery_capacity(struct hid_device *hid_dev, int voltage)
13571427 * there are a few devices that use different battery technology.
13581428 */
13591429
1360- static const int voltages [] = {
1430+ static const int voltages [100 ] = {
13611431 4186 , 4156 , 4143 , 4133 , 4122 , 4113 , 4103 , 4094 , 4086 , 4075 ,
13621432 4067 , 4059 , 4051 , 4043 , 4035 , 4027 , 4019 , 4011 , 4003 , 3997 ,
13631433 3989 , 3983 , 3976 , 3969 , 3961 , 3955 , 3949 , 3942 , 3935 , 3929 ,
@@ -1372,8 +1442,6 @@ static int hidpp20_map_battery_capacity(struct hid_device *hid_dev, int voltage)
13721442
13731443 int i ;
13741444
1375- BUILD_BUG_ON (ARRAY_SIZE (voltages ) != 100 );
1376-
13771445 if (unlikely (voltage < 3500 || voltage >= 5000 ))
13781446 hid_warn_once (hid_dev ,
13791447 "%s: possibly using the wrong voltage curve\n" ,
@@ -1745,6 +1813,164 @@ static int hidpp_set_wireless_feature_index(struct hidpp_device *hidpp)
17451813 return ret ;
17461814}
17471815
1816+ /* -------------------------------------------------------------------------- */
1817+ /* 0x1f20: ADC measurement */
1818+ /* -------------------------------------------------------------------------- */
1819+
1820+ #define HIDPP_PAGE_ADC_MEASUREMENT 0x1f20
1821+
1822+ #define CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT 0x00
1823+
1824+ #define EVENT_ADC_MEASUREMENT_STATUS_BROADCAST 0x00
1825+
1826+ static int hidpp20_map_adc_measurement_1f20_capacity (struct hid_device * hid_dev , int voltage )
1827+ {
1828+ /* NB: This voltage curve doesn't necessarily map perfectly to all
1829+ * devices that implement the ADC_MEASUREMENT feature. This is because
1830+ * there are a few devices that use different battery technology.
1831+ *
1832+ * Adapted from:
1833+ * https://github.com/Sapd/HeadsetControl/blob/acd972be0468e039b93aae81221f20a54d2d60f7/src/devices/logitech_g633_g933_935.c#L44-L52
1834+ */
1835+ static const int voltages [100 ] = {
1836+ 4030 , 4024 , 4018 , 4011 , 4003 , 3994 , 3985 , 3975 , 3963 , 3951 ,
1837+ 3937 , 3922 , 3907 , 3893 , 3880 , 3868 , 3857 , 3846 , 3837 , 3828 ,
1838+ 3820 , 3812 , 3805 , 3798 , 3791 , 3785 , 3779 , 3773 , 3768 , 3762 ,
1839+ 3757 , 3752 , 3747 , 3742 , 3738 , 3733 , 3729 , 3724 , 3720 , 3716 ,
1840+ 3712 , 3708 , 3704 , 3700 , 3696 , 3692 , 3688 , 3685 , 3681 , 3677 ,
1841+ 3674 , 3670 , 3667 , 3663 , 3660 , 3657 , 3653 , 3650 , 3646 , 3643 ,
1842+ 3640 , 3637 , 3633 , 3630 , 3627 , 3624 , 3620 , 3617 , 3614 , 3611 ,
1843+ 3608 , 3604 , 3601 , 3598 , 3595 , 3592 , 3589 , 3585 , 3582 , 3579 ,
1844+ 3576 , 3573 , 3569 , 3566 , 3563 , 3560 , 3556 , 3553 , 3550 , 3546 ,
1845+ 3543 , 3539 , 3536 , 3532 , 3529 , 3525 , 3499 , 3466 , 3433 , 3399 ,
1846+ };
1847+
1848+ int i ;
1849+
1850+ if (voltage == 0 )
1851+ return 0 ;
1852+
1853+ if (unlikely (voltage < 3400 || voltage >= 5000 ))
1854+ hid_warn_once (hid_dev ,
1855+ "%s: possibly using the wrong voltage curve\n" ,
1856+ __func__ );
1857+
1858+ for (i = 0 ; i < ARRAY_SIZE (voltages ); i ++ ) {
1859+ if (voltage >= voltages [i ])
1860+ return ARRAY_SIZE (voltages ) - i ;
1861+ }
1862+
1863+ return 0 ;
1864+ }
1865+
1866+ static int hidpp20_map_adc_measurement_1f20 (u8 data [3 ], int * voltage )
1867+ {
1868+ int status ;
1869+ u8 flags ;
1870+
1871+ flags = data [2 ];
1872+
1873+ switch (flags ) {
1874+ case 0x01 :
1875+ status = POWER_SUPPLY_STATUS_DISCHARGING ;
1876+ break ;
1877+ case 0x03 :
1878+ status = POWER_SUPPLY_STATUS_CHARGING ;
1879+ break ;
1880+ case 0x07 :
1881+ status = POWER_SUPPLY_STATUS_FULL ;
1882+ break ;
1883+ case 0x0F :
1884+ default :
1885+ status = POWER_SUPPLY_STATUS_UNKNOWN ;
1886+ break ;
1887+ }
1888+
1889+ * voltage = get_unaligned_be16 (data );
1890+
1891+ dbg_hid ("Parsed 1f20 data as flag 0x%02x voltage %dmV\n" ,
1892+ flags , * voltage );
1893+
1894+ return status ;
1895+ }
1896+
1897+ /* Return value is whether the device is online */
1898+ static bool hidpp20_get_adc_measurement_1f20 (struct hidpp_device * hidpp ,
1899+ u8 feature_index ,
1900+ int * status , int * voltage )
1901+ {
1902+ struct hidpp_report response ;
1903+ int ret ;
1904+ u8 * params = (u8 * )response .fap .params ;
1905+
1906+ * status = POWER_SUPPLY_STATUS_UNKNOWN ;
1907+ * voltage = 0 ;
1908+ ret = hidpp_send_fap_command_sync (hidpp , feature_index ,
1909+ CMD_ADC_MEASUREMENT_GET_ADC_MEASUREMENT ,
1910+ NULL , 0 , & response );
1911+
1912+ if (ret > 0 ) {
1913+ hid_dbg (hidpp -> hid_dev , "%s: received protocol error 0x%02x\n" ,
1914+ __func__ , ret );
1915+ return false;
1916+ }
1917+
1918+ * status = hidpp20_map_adc_measurement_1f20 (params , voltage );
1919+ return true;
1920+ }
1921+
1922+ static int hidpp20_query_adc_measurement_info_1f20 (struct hidpp_device * hidpp )
1923+ {
1924+ u8 feature_type ;
1925+
1926+ if (hidpp -> battery .adc_measurement_feature_index == 0xff ) {
1927+ int ret ;
1928+
1929+ ret = hidpp_root_get_feature (hidpp , HIDPP_PAGE_ADC_MEASUREMENT ,
1930+ & hidpp -> battery .adc_measurement_feature_index ,
1931+ & feature_type );
1932+ if (ret )
1933+ return ret ;
1934+
1935+ hidpp -> capabilities |= HIDPP_CAPABILITY_ADC_MEASUREMENT ;
1936+ }
1937+
1938+ hidpp -> battery .online = hidpp20_get_adc_measurement_1f20 (hidpp ,
1939+ hidpp -> battery .adc_measurement_feature_index ,
1940+ & hidpp -> battery .status ,
1941+ & hidpp -> battery .voltage );
1942+ hidpp -> battery .capacity = hidpp20_map_adc_measurement_1f20_capacity (hidpp -> hid_dev ,
1943+ hidpp -> battery .voltage );
1944+ hidpp_update_usb_wireless_status (hidpp );
1945+
1946+ return 0 ;
1947+ }
1948+
1949+ static int hidpp20_adc_measurement_event_1f20 (struct hidpp_device * hidpp ,
1950+ u8 * data , int size )
1951+ {
1952+ struct hidpp_report * report = (struct hidpp_report * )data ;
1953+ int status , voltage ;
1954+
1955+ if (report -> fap .feature_index != hidpp -> battery .adc_measurement_feature_index ||
1956+ report -> fap .funcindex_clientid != EVENT_ADC_MEASUREMENT_STATUS_BROADCAST )
1957+ return 0 ;
1958+
1959+ status = hidpp20_map_adc_measurement_1f20 (report -> fap .params , & voltage );
1960+
1961+ hidpp -> battery .online = status != POWER_SUPPLY_STATUS_UNKNOWN ;
1962+
1963+ if (voltage != hidpp -> battery .voltage || status != hidpp -> battery .status ) {
1964+ hidpp -> battery .status = status ;
1965+ hidpp -> battery .voltage = voltage ;
1966+ hidpp -> battery .capacity = hidpp20_map_adc_measurement_1f20_capacity (hidpp -> hid_dev , voltage );
1967+ if (hidpp -> battery .ps )
1968+ power_supply_changed (hidpp -> battery .ps );
1969+ hidpp_update_usb_wireless_status (hidpp );
1970+ }
1971+ return 0 ;
1972+ }
1973+
17481974/* -------------------------------------------------------------------------- */
17491975/* 0x2120: Hi-resolution scrolling */
17501976/* -------------------------------------------------------------------------- */
@@ -3663,6 +3889,9 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
36633889 ret = hidpp20_battery_voltage_event (hidpp , data , size );
36643890 if (ret != 0 )
36653891 return ret ;
3892+ ret = hidpp20_adc_measurement_event_1f20 (hidpp , data , size );
3893+ if (ret != 0 )
3894+ return ret ;
36663895 }
36673896
36683897 if (hidpp -> capabilities & HIDPP_CAPABILITY_HIDPP10_BATTERY ) {
@@ -3786,6 +4015,7 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
37864015 hidpp -> battery .feature_index = 0xff ;
37874016 hidpp -> battery .solar_feature_index = 0xff ;
37884017 hidpp -> battery .voltage_feature_index = 0xff ;
4018+ hidpp -> battery .adc_measurement_feature_index = 0xff ;
37894019
37904020 if (hidpp -> protocol_major >= 2 ) {
37914021 if (hidpp -> quirks & HIDPP_QUIRK_CLASS_K750 )
@@ -3799,6 +4029,8 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
37994029 ret = hidpp20_query_battery_info_1004 (hidpp );
38004030 if (ret )
38014031 ret = hidpp20_query_battery_voltage_info (hidpp );
4032+ if (ret )
4033+ ret = hidpp20_query_adc_measurement_info_1f20 (hidpp );
38024034 }
38034035
38044036 if (ret )
@@ -3828,15 +4060,17 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
38284060
38294061 if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_MILEAGE ||
38304062 hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_PERCENTAGE ||
3831- hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
4063+ hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE ||
4064+ hidpp -> capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT )
38324065 battery_props [num_battery_props ++ ] =
38334066 POWER_SUPPLY_PROP_CAPACITY ;
38344067
38354068 if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_LEVEL_STATUS )
38364069 battery_props [num_battery_props ++ ] =
38374070 POWER_SUPPLY_PROP_CAPACITY_LEVEL ;
38384071
3839- if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE )
4072+ if (hidpp -> capabilities & HIDPP_CAPABILITY_BATTERY_VOLTAGE ||
4073+ hidpp -> capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT )
38404074 battery_props [num_battery_props ++ ] =
38414075 POWER_SUPPLY_PROP_VOLTAGE_NOW ;
38424076
@@ -4009,6 +4243,8 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
40094243 hidpp20_query_battery_voltage_info (hidpp );
40104244 else if (hidpp -> capabilities & HIDPP_CAPABILITY_UNIFIED_BATTERY )
40114245 hidpp20_query_battery_info_1004 (hidpp );
4246+ else if (hidpp -> capabilities & HIDPP_CAPABILITY_ADC_MEASUREMENT )
4247+ hidpp20_query_adc_measurement_info_1f20 (hidpp );
40124248 else
40134249 hidpp20_query_battery_info_1000 (hidpp );
40144250 }
@@ -4210,6 +4446,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
42104446
42114447 if (hidpp -> quirks & HIDPP_QUIRK_UNIFYING )
42124448 hidpp_unifying_init (hidpp );
4449+ else if (hid_is_usb (hidpp -> hid_dev ))
4450+ hidpp_serial_init (hidpp );
42134451
42144452 connected = hidpp_root_get_protocol_version (hidpp ) == 0 ;
42154453 atomic_set (& hidpp -> connected , connected );
@@ -4379,6 +4617,10 @@ static const struct hid_device_id hidpp_devices[] = {
43794617 { /* Logitech G Pro Gaming Mouse over USB */
43804618 HID_USB_DEVICE (USB_VENDOR_ID_LOGITECH , 0xC088 ) },
43814619
4620+ { /* G935 Gaming Headset */
4621+ HID_USB_DEVICE (USB_VENDOR_ID_LOGITECH , 0x0a87 ),
4622+ .driver_data = HIDPP_QUIRK_WIRELESS_STATUS },
4623+
43824624 { /* MX5000 keyboard over Bluetooth */
43834625 HID_BLUETOOTH_DEVICE (USB_VENDOR_ID_LOGITECH , 0xb305 ),
43844626 .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS },
0 commit comments