summaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorNikolai Kondrashov <spbnick@gmail.com>2019-02-10 12:14:04 +0200
committerBenjamin Tissoires <benjamin.tissoires@redhat.com>2019-02-21 12:00:54 +0100
commit8a47670c35e2a8e70753eabd96d4f8d8b3c0eeba (patch)
tree04f2534d1aa1d1eb94a1e6fedfae0995055591f5 /drivers/hid
parentfde44ac556359b0fd56e11b889686377392b7407 (diff)
downloadlinux-8a47670c35e2a8e70753eabd96d4f8d8b3c0eeba.tar.bz2
HID: uclogic: Support Gray-coded rotary encoders
Add support for converting Gray-coded rotary encoder input into dial input compatible with HID standard. Needed for Ugee G5 support. Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-uclogic-core.c29
-rw-r--r--drivers/hid/hid-uclogic-params.h8
2 files changed, 37 insertions, 0 deletions
diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index f5fb612daa1e..dfacb04308b1 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -37,6 +37,8 @@ struct uclogic_drvdata {
struct input_dev *pen_input;
/* In-range timer */
struct timer_list inrange_timer;
+ /* Last rotary encoder state, or U8_MAX for none */
+ u8 re_state;
};
/**
@@ -175,6 +177,7 @@ static int uclogic_probe(struct hid_device *hdev,
goto failure;
}
timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
+ drvdata->re_state = U8_MAX;
hid_set_drvdata(hdev, drvdata);
/* Initialize the device and retrieve interface parameters */
@@ -308,6 +311,32 @@ static int uclogic_raw_event(struct hid_device *hdev,
params->frame.dev_id_byte < size) {
data[params->frame.dev_id_byte] = 0xf;
}
+ /* If need to, and can, read rotary encoder state change */
+ if (params->frame.re_lsb > 0 &&
+ params->frame.re_lsb / 8 < size) {
+ unsigned int byte = params->frame.re_lsb / 8;
+ unsigned int bit = params->frame.re_lsb % 8;
+
+ u8 change;
+ u8 prev_state = drvdata->re_state;
+ /* Read Gray-coded state */
+ u8 state = (data[byte] >> bit) & 0x3;
+ /* Encode state change into 2-bit signed integer */
+ if ((prev_state == 1 && state == 0) ||
+ (prev_state == 2 && state == 3)) {
+ change = 1;
+ } else if ((prev_state == 2 && state == 0) ||
+ (prev_state == 1 && state == 3)) {
+ change = 3;
+ } else {
+ change = 0;
+ }
+ /* Write change */
+ data[byte] = (data[byte] & ~((u8)3 << bit)) |
+ (change << bit);
+ /* Remember state */
+ drvdata->re_state = state;
+ }
}
return 0;
diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h
index 4ba6ecc2b8b8..ba48b1c7a0e5 100644
--- a/drivers/hid/hid-uclogic-params.h
+++ b/drivers/hid/hid-uclogic-params.h
@@ -88,6 +88,12 @@ struct uclogic_params_frame {
*/
unsigned int id;
/*
+ * Number of the least-significant bit of the 2-bit state of a rotary
+ * encoder, in the report. Cannot point to a 2-bit field crossing a
+ * byte boundary. Zero if not present. Only valid if "id" is not zero.
+ */
+ unsigned int re_lsb;
+ /*
* Offset of the Wacom-style device ID byte in the report, to be set
* to pad device ID (0xf), for compatibility with Wacom drivers. Zero
* if no changes to the report should be made. Only valid if "id" is
@@ -168,6 +174,7 @@ extern int uclogic_params_init(struct uclogic_params *params,
".frame.desc_ptr = %p\n" \
".frame.desc_size = %u\n" \
".frame.id = %u\n" \
+ ".frame.re_lsb = %u\n" \
".frame.dev_id_byte = %u\n" \
".pen_frame_flag = 0x%02x\n"
@@ -185,6 +192,7 @@ extern int uclogic_params_init(struct uclogic_params *params,
(_params)->frame.desc_ptr, \
(_params)->frame.desc_size, \
(_params)->frame.id, \
+ (_params)->frame.re_lsb, \
(_params)->frame.dev_id_byte, \
(_params)->pen_frame_flag