diff options
author | Jiri Kosina <jkosina@suse.cz> | 2007-07-04 10:45:59 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2007-07-09 08:13:37 -0400 |
commit | 2c1d8aea2ca76df1b1de2aed23e3ceda2a044ed1 (patch) | |
tree | 84441a52707b1239e8395b282b986dfb5a9cd3f1 | |
parent | 3c5f4b25f3552c9bcb52eb956753a3c8140480b7 (diff) |
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: Jochen Eisinger <jochen@penguin-breeder.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-input.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 60de16a83c3e..bf7e307503cc 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -882,6 +882,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
882 | field->dpad = usage->code; | 882 | field->dpad = usage->code; |
883 | } | 883 | } |
884 | 884 | ||
885 | /* for those devices which produce Consumer volume usage as relative, | ||
886 | * we emulate pressing volumeup/volumedown appropriate number of times | ||
887 | * in hidinput_hid_event() | ||
888 | */ | ||
889 | if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && | ||
890 | (usage->code == ABS_VOLUME)) { | ||
891 | set_bit(KEY_VOLUMEUP, input->keybit); | ||
892 | set_bit(KEY_VOLUMEDOWN, input->keybit); | ||
893 | } | ||
894 | |||
885 | hid_resolv_event(usage->type, usage->code); | 895 | hid_resolv_event(usage->type, usage->code); |
886 | #ifdef CONFIG_HID_DEBUG | 896 | #ifdef CONFIG_HID_DEBUG |
887 | printk("\n"); | 897 | printk("\n"); |
@@ -972,6 +982,21 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
972 | if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ | 982 | if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ |
973 | return; | 983 | return; |
974 | 984 | ||
985 | if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && | ||
986 | (usage->code == ABS_VOLUME)) { | ||
987 | int count = abs(value); | ||
988 | int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN; | ||
989 | int i; | ||
990 | |||
991 | for (i = 0; i < count; i++) { | ||
992 | input_event(input, EV_KEY, direction, 1); | ||
993 | input_sync(input); | ||
994 | input_event(input, EV_KEY, direction, 0); | ||
995 | input_sync(input); | ||
996 | } | ||
997 | return; | ||
998 | } | ||
999 | |||
975 | input_event(input, usage->type, usage->code, value); | 1000 | input_event(input, usage->type, usage->code, value); |
976 | 1001 | ||
977 | if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) | 1002 | if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) |