Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c1d8aea authored by Jiri Kosina's avatar Jiri Kosina
Browse files

HID: handle cases of volume knobs generating relative values



There are some devices (for example Dell Multimedia Keyboard SK-8135) that have
a volume control knob which generates relative events instead of absolute.
hid-input maps them to ABS_VOLUME. HUT pages don't restrict volume to absolute
values.

Adding REL_VOLUME doesn't seem feasible, nothing knows how to handle it. This
patch translates relative ABS_VOLUME events into appropriate number of series
of VOLUME_UP or VOLUME_DOWN events respectively, so that userspace sees the
correct values in the end.

kernel.org bugzilla 5233

Reported-by: default avatarJochen Eisinger <jochen@penguin-breeder.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 3c5f4b25
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -882,6 +882,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
			field->dpad = usage->code;
	}

	/* for those devices which produce Consumer volume usage as relative,
	 * we emulate pressing volumeup/volumedown appropriate number of times
	 * in hidinput_hid_event()
	 */
	if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
			(usage->code == ABS_VOLUME)) {
		set_bit(KEY_VOLUMEUP, input->keybit);
		set_bit(KEY_VOLUMEDOWN, input->keybit);
	}

	hid_resolv_event(usage->type, usage->code);
#ifdef CONFIG_HID_DEBUG
	printk("\n");
@@ -972,6 +982,21 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
	if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
		return;

	if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
			(usage->code == ABS_VOLUME)) {
		int count = abs(value);
		int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
		int i;

		for (i = 0; i < count; i++) {
			input_event(input, EV_KEY, direction, 1);
			input_sync(input);
			input_event(input, EV_KEY, direction, 0);
			input_sync(input);
		}
		return;
	}

	input_event(input, usage->type, usage->code, value);

	if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))