diff options
author | Nikolai Kondrashov <spbnick@gmail.com> | 2019-02-10 12:14:04 +0200 |
---|---|---|
committer | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2019-02-21 12:00:54 +0100 |
commit | 8a47670c35e2a8e70753eabd96d4f8d8b3c0eeba (patch) | |
tree | 04f2534d1aa1d1eb94a1e6fedfae0995055591f5 /drivers | |
parent | fde44ac556359b0fd56e11b889686377392b7407 (diff) |
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')
-rw-r--r-- | drivers/hid/hid-uclogic-core.c | 29 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic-params.h | 8 |
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 |