diff options
Diffstat (limited to 'drivers/hid/hid-input.c')
| -rw-r--r-- | drivers/hid/hid-input.c | 63 | 
1 files changed, 61 insertions, 2 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 859aeb07542e..7fc967964dd8 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -340,6 +340,7 @@ static enum power_supply_property hidinput_battery_props[] = {  #define HID_BATTERY_QUIRK_PERCENT	(1 << 0) /* always reports percent */  #define HID_BATTERY_QUIRK_FEATURE	(1 << 1) /* ask for feature report */  #define HID_BATTERY_QUIRK_IGNORE	(1 << 2) /* completely ignore the battery */ +#define HID_BATTERY_QUIRK_AVOID_QUERY	(1 << 3) /* do not query the battery */  static const struct hid_device_id hid_battery_quirks[] = {  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, @@ -369,16 +370,28 @@ static const struct hid_device_id hid_battery_quirks[] = {  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH,  		USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD),  	  HID_BATTERY_QUIRK_IGNORE }, +	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_ASUS_TP420IA_TOUCHSCREEN), +	  HID_BATTERY_QUIRK_IGNORE },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN),  	  HID_BATTERY_QUIRK_IGNORE },  	{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),  	  HID_BATTERY_QUIRK_IGNORE }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L), +	  HID_BATTERY_QUIRK_AVOID_QUERY }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_MW), +	  HID_BATTERY_QUIRK_AVOID_QUERY }, +	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_PRO_SW), +	  HID_BATTERY_QUIRK_AVOID_QUERY },  	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),  	  HID_BATTERY_QUIRK_IGNORE },  	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100),  	  HID_BATTERY_QUIRK_IGNORE }, +	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_EU0009NV), +	  HID_BATTERY_QUIRK_IGNORE },  	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15),  	  HID_BATTERY_QUIRK_IGNORE }, +	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_13_AW0020NG), +	  HID_BATTERY_QUIRK_IGNORE },  	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN),  	  HID_BATTERY_QUIRK_IGNORE },  	{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN), @@ -477,7 +490,7 @@ static int hidinput_get_battery_property(struct power_supply *psy,  		if (dev->battery_status == HID_BATTERY_UNKNOWN)  			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;  		else -			val->intval = POWER_SUPPLY_STATUS_DISCHARGING; +			val->intval = dev->battery_charge_status;  		break;  	case POWER_SUPPLY_PROP_SCOPE: @@ -545,6 +558,7 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,  	dev->battery_max = max;  	dev->battery_report_type = report_type;  	dev->battery_report_id = field->report->id; +	dev->battery_charge_status = POWER_SUPPLY_STATUS_DISCHARGING;  	/*  	 * Stylus is normally not connected to the device and thus we @@ -554,6 +568,9 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,  	dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&  				   field->physical == HID_DG_STYLUS; +	if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY) +		dev->battery_avoid_query = true; +  	dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);  	if (IS_ERR(dev->battery)) {  		error = PTR_ERR(dev->battery); @@ -608,6 +625,20 @@ static void hidinput_update_battery(struct hid_device *dev, int value)  		power_supply_changed(dev->battery);  	}  } + +static bool hidinput_set_battery_charge_status(struct hid_device *dev, +					       unsigned int usage, int value) +{ +	switch (usage) { +	case HID_BAT_CHARGING: +		dev->battery_charge_status = value ? +					     POWER_SUPPLY_STATUS_CHARGING : +					     POWER_SUPPLY_STATUS_DISCHARGING; +		return true; +	} + +	return false; +}  #else  /* !CONFIG_HID_BATTERY_STRENGTH */  static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,  				  struct hid_field *field, bool is_percentage) @@ -622,6 +653,12 @@ static void hidinput_cleanup_battery(struct hid_device *dev)  static void hidinput_update_battery(struct hid_device *dev, int value)  {  } + +static bool hidinput_set_battery_charge_status(struct hid_device *dev, +					       unsigned int usage, int value) +{ +	return false; +}  #endif	/* CONFIG_HID_BATTERY_STRENGTH */  static bool hidinput_field_in_collection(struct hid_device *device, struct hid_field *field, @@ -781,6 +818,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel  			break;  		} +		if ((usage->hid & 0xf0) == 0xa0) {	/* SystemControl */ +			switch (usage->hid & 0xf) { +			case 0x9: map_key_clear(KEY_MICMUTE); break; +			default: goto ignore; +			} +			break; +		} +  		if ((usage->hid & 0xf0) == 0xb0) {	/* SC - Display */  			switch (usage->hid & 0xf) {  			case 0x05: map_key_clear(KEY_SWITCHVIDEOMODE); break; @@ -1086,6 +1131,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel  		case 0x0cd: map_key_clear(KEY_PLAYPAUSE);	break;  		case 0x0cf: map_key_clear(KEY_VOICECOMMAND);	break; +		case 0x0d5: map_key_clear(KEY_CAMERA_ACCESS_ENABLE);		break; +		case 0x0d6: map_key_clear(KEY_CAMERA_ACCESS_DISABLE);		break; +		case 0x0d7: map_key_clear(KEY_CAMERA_ACCESS_TOGGLE);		break;  		case 0x0d8: map_key_clear(KEY_DICTATE);		break;  		case 0x0d9: map_key_clear(KEY_EMOJI_PICKER);	break; @@ -1208,6 +1256,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel  			hidinput_setup_battery(device, HID_INPUT_REPORT, field, true);  			usage->type = EV_PWR;  			return; +		case HID_BAT_CHARGING: +			usage->type = EV_PWR; +			return;  		}  		goto unknown; @@ -1450,7 +1501,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct  		return;  	if (usage->type == EV_PWR) { -		hidinput_update_battery(hid, value); +		bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value); + +		if (!handled) +			hidinput_update_battery(hid, value); +  		return;  	} @@ -2306,3 +2361,7 @@ void hidinput_disconnect(struct hid_device *hid)  	cancel_work_sync(&hid->led_work);  }  EXPORT_SYMBOL_GPL(hidinput_disconnect); + +#ifdef CONFIG_HID_KUNIT_TEST +#include "hid-input-test.c" +#endif  |