FreeBSD Bugzilla – Attachment 222890 Details for
Bug 252236
atp(4): Need EVDEV support for modern input stack
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
wsp_evdev_support.patch
wsp.patch (text/plain), 47.22 KB, created by
Vladimir Kondratyev
on 2021-02-28 23:31:01 UTC
(
hide
)
Description:
wsp_evdev_support.patch
Filename:
MIME Type:
Creator:
Vladimir Kondratyev
Created:
2021-02-28 23:31:01 UTC
Size:
47.22 KB
patch
obsolete
>diff --git a/sys/dev/evdev/cdev.c b/sys/dev/evdev/cdev.c >index 66d00ad16ae..d124e691a7c 100644 >--- a/sys/dev/evdev/cdev.c >+++ b/sys/dev/evdev/cdev.c >@@ -621,7 +621,7 @@ evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, > MIN(len / sizeof(int32_t) - 1, MAXIMAL_MT_SLOT(evdev) + 1); > for (int i = 0; i < nvalues; i++) > ((int32_t *)data)[i + 1] = >- evdev_get_mt_value(evdev, i, code); >+ evdev_mt_get_value(evdev, i, code); > return (0); > > case EVIOCGKEY(0): >diff --git a/sys/dev/evdev/evdev.c b/sys/dev/evdev/evdev.c >index 6c7dec284ef..4daae17237f 100644 >--- a/sys/dev/evdev/evdev.c >+++ b/sys/dev/evdev/evdev.c >@@ -93,15 +93,6 @@ static void evdev_start_repeat(struct evdev_dev *, uint16_t); > static void evdev_stop_repeat(struct evdev_dev *); > static int evdev_check_event(struct evdev_dev *, uint16_t, uint16_t, int32_t); > >-static inline void >-bit_change(bitstr_t *bitstr, int bit, int value) >-{ >- if (value) >- bit_set(bitstr, bit); >- else >- bit_clear(bitstr, bit); >-} >- > struct evdev_dev * > evdev_alloc(void) > { >@@ -726,8 +717,8 @@ evdev_modify_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, > else if (!ABS_IS_MT(code)) > old_value = evdev->ev_absinfo[code].value; > else if (bit_test(evdev->ev_abs_flags, ABS_MT_SLOT)) >- old_value = evdev_get_mt_value(evdev, >- evdev_get_last_mt_slot(evdev), code); >+ old_value = evdev_mt_get_value(evdev, >+ evdev_mt_get_last_slot(evdev), code); > else /* Pass MT protocol type A events as is */ > break; > >@@ -807,7 +798,7 @@ evdev_sparse_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, > switch (code) { > case ABS_MT_SLOT: > /* Postpone ABS_MT_SLOT till next event */ >- evdev_set_last_mt_slot(evdev, value); >+ evdev_mt_set_last_slot(evdev, value); > return (EV_SKIP_EVENT); > > case ABS_MT_FIRST ... ABS_MT_LAST: >@@ -815,11 +806,11 @@ evdev_sparse_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, > if (!bit_test(evdev->ev_abs_flags, ABS_MT_SLOT)) > break; > /* Don`t repeat MT protocol type B events */ >- last_mt_slot = evdev_get_last_mt_slot(evdev); >- if (evdev_get_mt_value(evdev, last_mt_slot, code) >+ last_mt_slot = evdev_mt_get_last_slot(evdev); >+ if (evdev_mt_get_value(evdev, last_mt_slot, code) > == value) > return (EV_SKIP_EVENT); >- evdev_set_mt_value(evdev, last_mt_slot, code, value); >+ evdev_mt_set_value(evdev, last_mt_slot, code, value); > if (last_mt_slot != CURRENT_MT_SLOT(evdev)) { > CURRENT_MT_SLOT(evdev) = last_mt_slot; > evdev->ev_report_opened = true; >@@ -895,6 +886,7 @@ evdev_send_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, > > EVDEV_LOCK_ASSERT(evdev); > >+ evdev_modify_event(evdev, type, code, &value); > sparse = evdev_sparse_event(evdev, type, code, value); > switch (sparse) { > case EV_REPORT_MT_SLOT: >@@ -918,20 +910,16 @@ evdev_restore_after_kdb(struct evdev_dev *evdev) > EVDEV_LOCK_ASSERT(evdev); > > /* Report postponed leds */ >- for (code = 0; code < LED_CNT; code++) >- if (bit_test(evdev->ev_kdb_led_states, code)) >- evdev_send_event(evdev, EV_LED, code, >- !bit_test(evdev->ev_led_states, code)); >+ bit_foreach(evdev->ev_kdb_led_states, LED_CNT, code) >+ evdev_send_event(evdev, EV_LED, code, >+ !bit_test(evdev->ev_led_states, code)); > bit_nclear(evdev->ev_kdb_led_states, 0, LED_MAX); > > /* Release stuck keys (CTRL + ALT + ESC) */ > evdev_stop_repeat(evdev); >- for (code = 0; code < KEY_CNT; code++) { >- if (bit_test(evdev->ev_key_states, code)) { >- evdev_send_event(evdev, EV_KEY, code, KEY_EVENT_UP); >- evdev_send_event(evdev, EV_SYN, SYN_REPORT, 1); >- } >- } >+ bit_foreach(evdev->ev_key_states, KEY_CNT, code) >+ evdev_send_event(evdev, EV_KEY, code, KEY_EVENT_UP); >+ evdev_send_event(evdev, EV_SYN, SYN_REPORT, 1); > } > > int >@@ -962,15 +950,16 @@ evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, > evdev_restore_after_kdb(evdev); > } > >- evdev_modify_event(evdev, type, code, &value); > if (type == EV_SYN && code == SYN_REPORT && >- bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) >- evdev_send_mt_autorel(evdev); >- if (type == EV_SYN && code == SYN_REPORT && evdev->ev_report_opened && >- bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) >- evdev_send_mt_compat(evdev); >- evdev_send_event(evdev, type, code, value); >+ bit_test(evdev->ev_abs_flags, ABS_MT_SLOT)) >+ evdev_mt_sync_frame(evdev); >+ else >+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK) && >+ evdev_mt_record_event(evdev, type, code, value)) >+ goto exit; > >+ evdev_send_event(evdev, type, code, value); >+exit: > EVDEV_EXIT(evdev); > > return (0); >diff --git a/sys/dev/evdev/evdev.h b/sys/dev/evdev/evdev.h >index 30d6a106d8b..40f53a03f6b 100644 >--- a/sys/dev/evdev/evdev.h >+++ b/sys/dev/evdev/evdev.h >@@ -90,6 +90,7 @@ extern int evdev_sysmouse_t_axis; > * current MT protocol type B report */ > #define EVDEV_FLAG_EXT_EPOCH 0x03 /* evdev_push_* is allways called with > * input (global) epoch entered */ >+#define EVDEV_FLAG_MT_TRACK 0x04 /* Assign touch to slot by evdev */ > #define EVDEV_FLAG_MAX 0x1F > #define EVDEV_FLAG_CNT (EVDEV_FLAG_MAX + 1) > >@@ -102,6 +103,29 @@ struct evdev_methods > evdev_keycode_t *ev_set_keycode; > }; > >+union evdev_mt_slot { >+ int32_t states[MT_CNT]; >+ struct { >+ int32_t maj; /* ABS_MT_TOUCH_MAJOR */ >+ int32_t min; /* ABS_MT_TOUCH_MINOR */ >+ int32_t w_maj; /* ABS_MT_WIDTH_MAJOR */ >+ int32_t w_min; /* ABS_MT_WIDTH_MINOR */ >+ int32_t ori; /* ABS_MT_ORIENTATION */ >+ int32_t x; /* ABS_MT_POSITION_X */ >+ int32_t y; /* ABS_MT_POSITION_Y */ >+ int32_t type; /* ABS_MT_TOOL_TYPE */ >+ int32_t blob_id; /* ABS_MT_BLOB_ID */ >+ int32_t id; /* ABS_MT_TRACKING_ID */ >+ int32_t p; /* ABS_MT_PRESSURE */ >+ int32_t dist; /* ABS_MT_DISTANCE */ >+ int32_t tool_x; /* ABS_MT_TOOL_X */ >+ int32_t tool_y; /* ABS_MT_TOOL_Y */ >+ }; >+}; >+_Static_assert(offsetof(union evdev_mt_slot, tool_y) == >+ offsetof(union evdev_mt_slot, states[ABS_MT_INDEX(ABS_MT_TOOL_Y)]), >+ "evdev_mt_slot array members does not match their structure aliases"); >+ > /* Input device interface: */ > struct evdev_dev *evdev_alloc(void); > void evdev_free(struct evdev_dev *); >@@ -131,11 +155,18 @@ void evdev_set_flag(struct evdev_dev *, uint16_t); > void *evdev_get_softc(struct evdev_dev *); > > /* Multitouch related functions: */ >-int32_t evdev_get_mt_slot_by_tracking_id(struct evdev_dev *, int32_t); >-void evdev_support_nfingers(struct evdev_dev *, int32_t); >+int evdev_get_mt_slot_by_tracking_id(struct evdev_dev *, int32_t); > void evdev_support_mt_compat(struct evdev_dev *); >-void evdev_push_nfingers(struct evdev_dev *, int32_t); > void evdev_push_mt_compat(struct evdev_dev *); >+int evdev_mt_push_slot(struct evdev_dev *, int, union evdev_mt_slot *); >+int evdev_mt_push_frame(struct evdev_dev *, union evdev_mt_slot *, int); >+union evdev_mt_slot *evdev_mt_get_match_slots(struct evdev_dev *); >+void evdev_mt_push_autorel(struct evdev_dev *); >+static __inline int >+evdev_mt_id_to_slot(struct evdev_dev *evdev, int32_t id) >+{ >+ return (evdev_get_mt_slot_by_tracking_id(evdev, id)); >+} > > /* Utility functions: */ > uint16_t evdev_hid2key(int); >@@ -144,6 +175,8 @@ uint16_t evdev_scancode2key(int *, int); > void evdev_push_mouse_btn(struct evdev_dev *, int); > void evdev_push_leds(struct evdev_dev *, int); > void evdev_push_repeats(struct evdev_dev *, keyboard_t *); >+void evdev_support_nfingers(struct evdev_dev *, int); >+void evdev_push_nfingers(struct evdev_dev *, int); > > /* Event reporting shortcuts: */ > static __inline int >diff --git a/sys/dev/evdev/evdev_mt.c b/sys/dev/evdev/evdev_mt.c >index 1f9c9756db0..34a2ae6735b 100644 >--- a/sys/dev/evdev/evdev_mt.c >+++ b/sys/dev/evdev/evdev_mt.c >@@ -1,5 +1,5 @@ > /*- >- * Copyright (c) 2016 Vladimir Kondratyev <wulf@FreeBSD.org> >+ * Copyright (c) 2016, 2020 Vladimir Kondratyev <wulf@FreeBSD.org> > * All rights reserved. > * > * Redistribution and use in source and binary forms, with or without >@@ -25,6 +25,21 @@ > * > * $FreeBSD$ > */ >+/*- >+ * Copyright (c) 2015, 2016 Ulf Brosziewski >+ * >+ * Permission to use, copy, modify, and distribute this software for any >+ * purpose with or without fee is hereby granted, provided that the above >+ * copyright notice and this permission notice appear in all copies. >+ * >+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES >+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF >+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR >+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES >+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN >+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF >+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. >+ */ > > #include <sys/param.h> > #include <sys/lock.h> >@@ -42,54 +57,78 @@ > #define debugf(fmt, args...) > #endif > >-static uint16_t evdev_fngmap[] = { >- BTN_TOOL_FINGER, >- BTN_TOOL_DOUBLETAP, >- BTN_TOOL_TRIPLETAP, >- BTN_TOOL_QUADTAP, >- BTN_TOOL_QUINTTAP, >-}; >+#define FOREACHBIT(v, i) \ >+ for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1) > >-static uint16_t evdev_mtstmap[][2] = { >- { ABS_MT_POSITION_X, ABS_X }, >- { ABS_MT_POSITION_Y, ABS_Y }, >- { ABS_MT_PRESSURE, ABS_PRESSURE }, >- { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH }, >-}; >+#define INITIAL_SLOT -1 > >-struct evdev_mt_slot { >- uint64_t ev_report; >- int32_t ev_mt_states[MT_CNT]; >+struct { >+ uint16_t mt; >+ uint16_t st; >+ int32_t max; >+} static evdev_mtstmap[] = { >+ { ABS_MT_POSITION_X, ABS_X, 0 }, >+ { ABS_MT_POSITION_Y, ABS_Y, 0 }, >+ { ABS_MT_PRESSURE, ABS_PRESSURE, 255 }, >+ { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH, 15 }, > }; > > struct evdev_mt { >- int32_t ev_mt_last_reported_slot; >- struct evdev_mt_slot ev_mt_slots[]; >+ int last_reported_slot; >+ bool type_a; >+ u_int mtst_events; >+ /* the set of slots with active touches */ >+ u_int touches; >+ /* the set of slots with unsynchronized state */ >+ u_int frame; >+ /* the set of slots to match with active touches */ >+ u_int match_frame; >+ int match_slot; >+ union evdev_mt_slot *match_slots; >+ int *matrix; >+ union evdev_mt_slot slots[]; > }; >+_Static_assert(MAX_MT_SLOTS <= sizeof(((struct evdev_mt *)0)->touches) * 8, >+ "MAX_MT_SLOTS exceeds size of touches member of struct evdev_mt"); >+ >+static void evdev_mt_send_st_compat(struct evdev_dev *); >+static void evdev_mt_send_autorel(struct evdev_dev *); >+static void evdev_mt_replay_events(struct evdev_dev *); > > void > evdev_mt_init(struct evdev_dev *evdev) > { >- int32_t slot, slots; >+ struct evdev_mt *mt; >+ int slot, slots; >+ size_t size = offsetof(struct evdev_mt, slots); > > slots = MAXIMAL_MT_SLOT(evdev) + 1; >+ size += sizeof(mt->slots[0]) * slots; >+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { >+ size += sizeof(mt->match_slots[0]) * slots; >+ size += sizeof(mt->matrix[0]) * (slots + 6) * slots; >+ } > >- evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) + >- sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO); >+ mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO); >+ evdev->ev_mt = mt; > >- /* Initialize multitouch protocol type B states */ >- for (slot = 0; slot < slots; slot++) { >+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { > /* >- * .ev_report should not be initialized to initial value of >- * report counter (0) as it brokes free slot detection in >- * evdev_get_mt_slot_by_tracking_id. So initialize it to -1 >+ * We can not distinct MT type A/B protocols by MT_SLOT event >+ * as it defines number of touches so use ABS_MT_TRACKING_ID. > */ >- evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) { >- .ev_report = 0xFFFFFFFFFFFFFFFFULL, >- .ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1, >- }; >+ if (!bit_test(evdev->ev_abs_flags, ABS_MT_TRACKING_ID)) >+ mt->type_a = true; >+ evdev_support_abs(evdev, >+ ABS_MT_TRACKING_ID, -1, slots - 1, 0, 0, 0); >+ mt->match_slots = evdev->ev_mt->slots + slots; >+ mt->matrix = (int *)(mt->match_slots + slots); > } > >+ /* Initialize multitouch protocol type B states */ >+ for (slot = 0; slot < slots; slot++) >+ mt->slots[slot].id = -1; >+ > if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) > evdev_support_mt_compat(evdev); > } >@@ -97,155 +136,451 @@ evdev_mt_init(struct evdev_dev *evdev) > void > evdev_mt_free(struct evdev_dev *evdev) > { >- > free(evdev->ev_mt, M_EVDEV); > } > >-int32_t >-evdev_get_last_mt_slot(struct evdev_dev *evdev) >+void >+evdev_mt_sync_frame(struct evdev_dev *evdev) >+{ >+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) >+ evdev_mt_replay_events(evdev); >+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) >+ evdev_mt_send_autorel(evdev); >+ if (evdev->ev_report_opened && >+ bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) >+ evdev_mt_send_st_compat(evdev); >+ evdev->ev_mt->frame = 0; >+} >+ >+static void >+evdev_mt_send_slot(struct evdev_dev *evdev, int slot, >+ union evdev_mt_slot *state) > { >+ int i; >+ >+ EVDEV_LOCK_ASSERT(evdev); >+ MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); > >- return (evdev->ev_mt->ev_mt_last_reported_slot); >+ evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); >+ if (state == NULL) { >+ evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1); >+ return; >+ } >+ bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i) >+ evdev_send_event(evdev, EV_ABS, i, >+ state->states[ABS_MT_INDEX(i)]); > } > >-void >-evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot) >+int >+evdev_mt_push_slot(struct evdev_dev *evdev, int slot, >+ union evdev_mt_slot *state) > { >+ struct evdev_mt *mt = evdev->ev_mt; >+ >+ if (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev)) >+ return (EINVAL); > >- evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count; >- evdev->ev_mt->ev_mt_last_reported_slot = slot; >+ EVDEV_ENTER(evdev); >+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { >+ evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot); >+ if (state != NULL) >+ mt->match_slots[mt->match_slot] = *state; >+ else >+ evdev_mt_record_event(evdev, EV_ABS, >+ ABS_MT_TRACKING_ID, -1); >+ } else >+ evdev_mt_send_slot(evdev, slot, state); >+ EVDEV_EXIT(evdev); >+ >+ return (0); > } > >-inline int32_t >-evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code) >+/* >+ * Find a minimum-weight matching for an m-by-n matrix. >+ * >+ * m must be greater than or equal to n. The size of the buffer must be >+ * at least 3m + 3n. >+ * >+ * On return, the first m elements of the buffer contain the row-to- >+ * column mappings, i.e., buffer[i] is the column index for row i, or -1 >+ * if there is no assignment for that row (which may happen if n < m). >+ * >+ * Wrong results because of overflows will not occur with input values >+ * in the range of 0 to INT_MAX / 2 inclusive. >+ * >+ * The function applies the Dinic-Kronrod algorithm. It is not modern or >+ * popular, but it seems to be a good choice for small matrices at least. >+ * The original form of the algorithm is modified as follows: There is no >+ * initial search for row minima, the initial assignments are in a >+ * "virtual" column with the index -1 and zero values. This permits inputs >+ * with n < m, and it simplifies the reassignments. >+ */ >+static void >+evdev_mt_matching(int *matrix, int m, int n, int *buffer) >+{ >+ int i, j, k, d, e, row, col, delta; >+ int *p; >+ int *r2c = buffer; /* row-to-column assignments */ >+ int *red = r2c + m; /* reduced values of the assignments */ >+ int *mc = red + m; /* row-wise minimal elements of cs */ >+ int *cs = mc + m; /* the column set */ >+ int *c2r = cs + n; /* column-to-row assignments in cs */ >+ int *cd = c2r + n; /* column deltas (reduction) */ >+ >+ for (p = r2c; p < red; *p++ = -1) {} >+ for (; p < mc; *p++ = 0) {} >+ for (col = 0; col < n; col++) { >+ delta = INT_MAX; >+ for (i = 0, p = matrix + col; i < m; i++, p += n) { >+ d = *p - red[i]; >+ if (d < delta || (d == delta && r2c[i] < 0)) { >+ delta = d; >+ row = i; >+ } >+ } >+ cd[col] = delta; >+ if (r2c[row] < 0) { >+ r2c[row] = col; >+ continue; >+ } >+ for (p = mc; p < cs; *p++ = col) {} >+ for (k = 0; (j = r2c[row]) >= 0;) { >+ cs[k++] = j; >+ c2r[j] = row; >+ mc[row] -= n; >+ delta = INT_MAX; >+ for (i = 0, p = matrix; i < m; i++, p += n) >+ if (mc[i] >= 0) { >+ d = p[mc[i]] - cd[mc[i]]; >+ e = p[j] - cd[j]; >+ if (e < d) { >+ d = e; >+ mc[i] = j; >+ } >+ d -= red[i]; >+ if (d < delta || (d == delta >+ && r2c[i] < 0)) { >+ delta = d; >+ row = i; >+ } >+ } >+ cd[col] += delta; >+ for (i = 0; i < k; i++) { >+ cd[cs[i]] += delta; >+ red[c2r[cs[i]]] -= delta; >+ } >+ } >+ for (j = mc[row]; (r2c[row] = j) != col;) { >+ row = c2r[j]; >+ j = mc[row] + n; >+ } >+ } >+} >+ >+/* >+ * Assign slot numbers to the points in the pt array, and update all slots by >+ * calling evdev_mt_send_slot internally. The slot numbers are passed to the >+ * caller in the pt->slot fields. >+ * >+ * The slot assignment pairs the points with points of the previous frame in >+ * such a way that the sum of the squared distances is minimal. Using >+ * squares instead of simple distances favours assignments with more uniform >+ * distances, and it is faster. >+ */ >+static void >+evdev_mt_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) > { >+ struct evdev_mt *mt = evdev->ev_mt; >+ int i, j, m, n, dx, dy, slot, num_touches; >+ int *p, *r2c, *c2r; >+ u_int touches; >+ >+ EVDEV_LOCK_ASSERT(evdev); >+ MPASS(mt->matrix != NULL); >+ MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); >+ >+ p = mt->matrix; >+ touches = mt->touches; >+ num_touches = bitcount(touches); >+ if (num_touches >= size) { >+ FOREACHBIT(touches, slot) >+ for (i = 0; i < size; i++) { >+ dx = pt[i].x - mt->slots[slot].x; >+ dy = pt[i].y - mt->slots[slot].y; >+ *p++ = dx * dx + dy * dy; >+ } >+ m = num_touches; >+ n = size; >+ } else { >+ for (i = 0; i < size; i++) >+ FOREACHBIT(touches, slot) { >+ dx = pt[i].x - mt->slots[slot].x; >+ dy = pt[i].y - mt->slots[slot].y; >+ *p++ = dx * dx + dy * dy; >+ } >+ m = size; >+ n = num_touches; >+ } >+ evdev_mt_matching(mt->matrix, m, n, p); >+ >+ r2c = p; >+ c2r = p + m; >+ for (i = 0; i < m; i++) >+ if ((j = r2c[i]) >= 0) >+ c2r[j] = i; >+ >+ p = (n == size ? c2r : r2c); >+ for (i = 0; i < size; i++) >+ if (*p++ < 0) { >+ slot = ffs(~(mt->touches | mt->frame)) - 1; >+ if (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev)) >+ break; >+ pt[i].id = slot; >+ evdev_mt_send_slot(evdev, slot, pt + i); >+ } > >- return (evdev->ev_mt-> >- ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]); >+ p = (n == size ? r2c : c2r); >+ FOREACHBIT(touches, slot) >+ if ((i = *p++) >= 0) { >+ pt[i].id = slot; >+ evdev_mt_send_slot(evdev, slot, pt + i); >+ } else { >+ evdev_mt_send_slot(evdev, slot, NULL); >+ } > } > >-inline void >-evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code, >- int32_t value) >+int >+evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) > { >+ if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1) >+ return (EINVAL); >+ >+ EVDEV_ENTER(evdev); >+ evdev_mt_frame(evdev, pt, size); >+ EVDEV_EXIT(evdev); > >- evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] = >- value; >+ return (0); > } > >-int32_t >-evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) >+bool >+evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, >+ int32_t value) > { >- int32_t tr_id, slot, free_slot = -1; >+ struct evdev_mt *mt = evdev->ev_mt; > >- for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { >- tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID); >- if (tr_id == tracking_id) >- return (slot); >- /* >- * Its possible that slot will be reassigned in a place of just >- * released one within the same report. To avoid this compare >- * report counter with slot`s report number updated with each >- * ABS_MT_TRACKING_ID change. >- */ >- if (free_slot == -1 && tr_id == -1 && >- evdev->ev_mt->ev_mt_slots[slot].ev_report != >- evdev->ev_report_count) >- free_slot = slot; >+ EVDEV_LOCK_ASSERT(evdev); >+ >+ switch (type) { >+ case EV_SYN: >+ if (code == SYN_MT_REPORT) { >+ /* MT protocol type A support */ >+ KASSERT(mt->type_a, ("Not a MT type A protocol")); >+ mt->match_frame |= 1U << mt->match_slot; >+ mt->match_slot++; >+ return (true); >+ } >+ break; >+ case EV_ABS: >+ if (code == ABS_MT_SLOT) { >+ /* MT protocol type B support */ >+ KASSERT(!mt->type_a, ("Not a MT type B protocol")); >+ KASSERT(value >= 0, ("Negative slot number")); >+ mt->match_slot = value; >+ mt->match_frame |= 1U << mt->match_slot; >+ return (true); >+ } else if (code == ABS_MT_TRACKING_ID) { >+ KASSERT(!mt->type_a, ("Not a MT type B protocol")); >+ if (value == -1) >+ mt->match_frame &= ~(1U << mt->match_slot); >+ return (true); >+ } else if (ABS_IS_MT(code)) { >+ KASSERT(mt->match_slot >= 0, ("Negative slot")); >+ KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev), >+ ("Slot number too big")); >+ mt->match_slots[mt->match_slot]. >+ states[ABS_MT_INDEX(code)] = value; >+ return (true); >+ } >+ break; >+ default: >+ break; > } > >- return (free_slot); >+ return (false); > } > >-void >-evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers) >+static void >+evdev_mt_replay_events(struct evdev_dev *evdev) > { >- int32_t i; >+ struct evdev_mt *mt = evdev->ev_mt; >+ int slot, size = 0; >+ >+ EVDEV_LOCK_ASSERT(evdev); > >- for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++) >- evdev_support_key(evdev, evdev_fngmap[i]); >+ FOREACHBIT(mt->match_frame, slot) { >+ if (slot != size) >+ mt->match_slots[size] = mt->match_slots[slot]; >+ size++; >+ } >+ if (size != 0) >+ evdev_mt_frame(evdev, mt->match_slots, size); >+ mt->match_slot = mt->type_a ? 0 : INITIAL_SLOT; >+ mt->match_frame = 0; > } > >-void >-evdev_support_mt_compat(struct evdev_dev *evdev) >+union evdev_mt_slot * >+evdev_mt_get_match_slots(struct evdev_dev *evdev) > { >- int32_t i; >+ return (evdev->ev_mt->match_slots); >+} > >- if (evdev->ev_absinfo == NULL) >- return; >+int >+evdev_mt_get_last_slot(struct evdev_dev *evdev) >+{ >+ return (evdev->ev_mt->last_reported_slot); >+} > >- evdev_support_event(evdev, EV_KEY); >- evdev_support_key(evdev, BTN_TOUCH); >+void >+evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) >+{ >+ struct evdev_mt *mt = evdev->ev_mt; > >- /* Touchscreens should not advertise tap tool capabilities */ >- if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) >- evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); >+ MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); > >- /* Echo 0-th MT-slot as ST-slot */ >- for (i = 0; i < nitems(evdev_mtstmap); i++) >- if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0])) >- evdev_support_abs(evdev, evdev_mtstmap[i][1], >- evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum, >- evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum, >- evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz, >- evdev->ev_absinfo[evdev_mtstmap[i][0]].flat, >- evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution); >+ mt->frame |= 1U << slot; >+ mt->last_reported_slot = slot; > } > >-static int32_t >-evdev_count_fingers(struct evdev_dev *evdev) >+int32_t >+evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) > { >- int32_t nfingers = 0, i; >+ struct evdev_mt *mt = evdev->ev_mt; > >- for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++) >- if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1) >- nfingers++; >+ MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); > >- return (nfingers); >+ return (mt->slots[slot].states[ABS_MT_INDEX(code)]); > } > >-static void >-evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers) >+void >+evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, >+ int32_t value) > { >- int32_t i; >+ struct evdev_mt *mt = evdev->ev_mt; > >- EVDEV_LOCK_ASSERT(evdev); >+ MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); >+ >+ if (code == ABS_MT_TRACKING_ID) { >+ if (value != -1) >+ mt->touches |= 1U << slot; >+ else >+ mt->touches &= ~(1U << slot); >+ } >+ mt->slots[slot].states[ABS_MT_INDEX(code)] = value; >+} > >- if (nfingers > nitems(evdev_fngmap)) >- nfingers = nitems(evdev_fngmap); >+int >+evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) >+{ >+ struct evdev_mt *mt = evdev->ev_mt; >+ int slot; >+ >+ KASSERT(!mt->type_a, ("Not a MT type B protocol")); >+ >+ /* >+ * Ignore tracking_id if slot assignment is performed by evdev. >+ * Events are written sequentially to temporary matching buffer. >+ */ >+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { >+ if (mt->match_slot == INITIAL_SLOT) >+ return (0); >+ if ((mt->match_frame & (1U << mt->match_slot)) == 0) >+ return (mt->match_slot); >+ if (mt->match_slot >= MAXIMAL_MT_SLOT(evdev)) >+ return (-1); >+ return (mt->match_slot + 1); >+ } >+ FOREACHBIT(mt->touches, slot) >+ if (mt->slots[slot].id == tracking_id) >+ return (slot); >+ /* >+ * Do not allow allocation of new slot in a place of just >+ * released one within the same report. >+ */ >+ return (ffs(~(mt->touches | mt->frame)) - 1); >+} > >- for (i = 0; i < nitems(evdev_fngmap); i++) >- evdev_send_event(evdev, EV_KEY, evdev_fngmap[i], >- nfingers == i + 1); >+static inline int32_t >+evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax) >+{ >+ if (stmax != 0 && mtmax != mtmin) { >+ value = (value - mtmin) * stmax / (mtmax - mtmin); >+ value = MAX(MIN(value, stmax), 0); >+ } >+ return (value); > } > > void >-evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers) >+evdev_support_mt_compat(struct evdev_dev *evdev) > { >+ struct input_absinfo *ai; >+ int i; > >- EVDEV_ENTER(evdev); >- evdev_send_nfingers(evdev, nfingers); >- EVDEV_EXIT(evdev); >+ if (evdev->ev_absinfo == NULL) >+ return; >+ >+ evdev_support_event(evdev, EV_KEY); >+ evdev_support_key(evdev, BTN_TOUCH); >+ >+ /* Touchscreens should not advertise tap tool capabilities */ >+ if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) >+ evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); >+ >+ /* Echo 0-th MT-slot as ST-slot */ >+ for (i = 0; i < nitems(evdev_mtstmap); i++) { >+ if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) || >+ bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st)) >+ continue; >+ ai = evdev->ev_absinfo + evdev_mtstmap[i].mt; >+ evdev->ev_mt->mtst_events |= 1U << i; >+ if (evdev_mtstmap[i].max != 0) >+ evdev_support_abs(evdev, evdev_mtstmap[i].st, >+ 0, >+ evdev_mtstmap[i].max, >+ 0, >+ evdev_mt_normalize( >+ ai->flat, 0, ai->maximum, evdev_mtstmap[i].max), >+ 0); >+ else >+ evdev_support_abs(evdev, evdev_mtstmap[i].st, >+ ai->minimum, >+ ai->maximum, >+ 0, >+ ai->flat, >+ ai->resolution); >+ } > } > >-void >-evdev_send_mt_compat(struct evdev_dev *evdev) >+static void >+evdev_mt_send_st_compat(struct evdev_dev *evdev) > { >- int32_t nfingers, i; >+ struct evdev_mt *mt = evdev->ev_mt; >+ int nfingers, i, st_slot; > > EVDEV_LOCK_ASSERT(evdev); > >- nfingers = evdev_count_fingers(evdev); >+ nfingers = bitcount(mt->touches); > evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); > >- if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1) >- /* Echo 0-th MT-slot as ST-slot */ >- for (i = 0; i < nitems(evdev_mtstmap); i++) >- if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1])) >- evdev_send_event(evdev, EV_ABS, >- evdev_mtstmap[i][1], >- evdev_get_mt_value(evdev, 0, >- evdev_mtstmap[i][0])); >+ /* Send first active MT-slot state as single touch report */ >+ st_slot = ffs(mt->touches) - 1; >+ if (st_slot != -1) >+ FOREACHBIT(mt->mtst_events, i) >+ evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st, >+ evdev_mt_normalize(evdev_mt_get_value(evdev, >+ st_slot, evdev_mtstmap[i].mt), >+ evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum, >+ evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum, >+ evdev_mtstmap[i].max)); > > /* Touchscreens should not report tool taps */ > if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) >@@ -260,24 +595,26 @@ evdev_push_mt_compat(struct evdev_dev *evdev) > { > > EVDEV_ENTER(evdev); >- evdev_send_mt_compat(evdev); >+ evdev_mt_send_st_compat(evdev); > EVDEV_EXIT(evdev); > } > >-void >-evdev_send_mt_autorel(struct evdev_dev *evdev) >+static void >+evdev_mt_send_autorel(struct evdev_dev *evdev) > { >- int32_t slot; >+ struct evdev_mt *mt = evdev->ev_mt; >+ int slot; > > EVDEV_LOCK_ASSERT(evdev); > >- for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { >- if (evdev->ev_mt->ev_mt_slots[slot].ev_report != >- evdev->ev_report_count && >- evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){ >- evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); >- evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, >- -1); >- } >- } >+ FOREACHBIT(mt->touches & ~mt->frame, slot) >+ evdev_mt_send_slot(evdev, slot, NULL); >+} >+ >+void >+evdev_mt_push_autorel(struct evdev_dev *evdev) >+{ >+ EVDEV_ENTER(evdev); >+ evdev_mt_send_autorel(evdev); >+ EVDEV_EXIT(evdev); > } >diff --git a/sys/dev/evdev/evdev_private.h b/sys/dev/evdev/evdev_private.h >index 19636823b80..1351fe53cc0 100644 >--- a/sys/dev/evdev/evdev_private.h >+++ b/sys/dev/evdev/evdev_private.h >@@ -247,6 +247,22 @@ struct evdev_client > (((client)->ec_buffer_ready + (client)->ec_buffer_size - \ > (client)->ec_buffer_head) % (client)->ec_buffer_size) > >+/* bitstring(3) helpers */ >+static inline void >+bit_change(bitstr_t *bitstr, int bit, int value) >+{ >+ if (value) >+ bit_set(bitstr, bit); >+ else >+ bit_clear(bitstr, bit); >+} >+#define bit_foreach_at(_bitstr, _start, _nbits, _iter) \ >+ for (bit_ffs_at((_bitstr), (_start), (_nbits), &(_iter)); \ >+ (_iter) != -1; \ >+ bit_ffs_at((_bitstr), (_iter) + 1, (_nbits), &(_iter))) >+#define bit_foreach(_bitstr, _nbits, _iter) \ >+ bit_foreach_at(_bitstr, /*start*/0, _nbits, _iter) >+ > /* Input device interface: */ > void evdev_send_event(struct evdev_dev *, uint16_t, uint16_t, int32_t); > int evdev_inject_event(struct evdev_dev *, uint16_t, uint16_t, int32_t); >@@ -269,14 +285,15 @@ void evdev_revoke_client(struct evdev_client *); > /* Multitouch related functions: */ > void evdev_mt_init(struct evdev_dev *); > void evdev_mt_free(struct evdev_dev *); >-int32_t evdev_get_last_mt_slot(struct evdev_dev *); >-void evdev_set_last_mt_slot(struct evdev_dev *, int32_t); >-int32_t evdev_get_mt_value(struct evdev_dev *, int32_t, int16_t); >-void evdev_set_mt_value(struct evdev_dev *, int32_t, int16_t, int32_t); >-void evdev_send_mt_compat(struct evdev_dev *); >-void evdev_send_mt_autorel(struct evdev_dev *); >+void evdev_mt_sync_frame(struct evdev_dev *); >+int evdev_mt_get_last_slot(struct evdev_dev *); >+void evdev_mt_set_last_slot(struct evdev_dev *, int); >+int32_t evdev_mt_get_value(struct evdev_dev *, int, int16_t); >+void evdev_mt_set_value(struct evdev_dev *, int, int16_t, int32_t); >+bool evdev_mt_record_event(struct evdev_dev *, uint16_t, uint16_t, int32_t); > > /* Utility functions: */ > void evdev_client_dumpqueue(struct evdev_client *); >+void evdev_send_nfingers(struct evdev_dev *, int); > > #endif /* _DEV_EVDEV_EVDEV_PRIVATE_H */ >diff --git a/sys/dev/evdev/evdev_utils.c b/sys/dev/evdev/evdev_utils.c >index fd696dc6ac2..754846b8d6e 100644 >--- a/sys/dev/evdev/evdev_utils.c >+++ b/sys/dev/evdev/evdev_utils.c >@@ -38,6 +38,7 @@ > #include <sys/systm.h> > > #include <dev/evdev/evdev.h> >+#include <dev/evdev/evdev_private.h> > #include <dev/evdev/input.h> > > #define NONE KEY_RESERVED >@@ -205,6 +206,14 @@ static uint16_t evdev_led_codes[] = { > LED_SCROLLL, /* SLKED */ > }; > >+static uint16_t evdev_nfinger_codes[] = { >+ BTN_TOOL_FINGER, >+ BTN_TOOL_DOUBLETAP, >+ BTN_TOOL_TRIPLETAP, >+ BTN_TOOL_QUADTAP, >+ BTN_TOOL_QUINTTAP, >+}; >+ > uint16_t > evdev_hid2key(int scancode) > { >@@ -300,3 +309,35 @@ evdev_push_repeats(struct evdev_dev *evdev, keyboard_t *kbd) > evdev_push_event(evdev, EV_REP, REP_DELAY, kbd->kb_delay1); > evdev_push_event(evdev, EV_REP, REP_PERIOD, kbd->kb_delay2); > } >+ >+void >+evdev_support_nfingers(struct evdev_dev *evdev, int nfingers) >+{ >+ int i; >+ >+ for (i = 0; i < MIN(nitems(evdev_nfinger_codes), nfingers); i++) >+ evdev_support_key(evdev, evdev_nfinger_codes[i]); >+} >+ >+void >+evdev_send_nfingers(struct evdev_dev *evdev, int nfingers) >+{ >+ int i; >+ >+ EVDEV_LOCK_ASSERT(evdev); >+ >+ if (nfingers > nitems(evdev_nfinger_codes)) >+ nfingers = nitems(evdev_nfinger_codes); >+ >+ for (i = 0; i < nitems(evdev_nfinger_codes); i++) >+ evdev_send_event(evdev, EV_KEY, evdev_nfinger_codes[i], >+ nfingers == i + 1); >+} >+ >+void >+evdev_push_nfingers(struct evdev_dev *evdev, int nfingers) >+{ >+ EVDEV_ENTER(evdev); >+ evdev_send_nfingers(evdev, nfingers); >+ EVDEV_EXIT(evdev); >+} >diff --git a/sys/dev/usb/input/wsp.c b/sys/dev/usb/input/wsp.c >index c44c4aceb30..3b021486775 100644 >--- a/sys/dev/usb/input/wsp.c >+++ b/sys/dev/usb/input/wsp.c >@@ -29,6 +29,8 @@ > #include <sys/cdefs.h> > __FBSDID("$FreeBSD$"); > >+#include "opt_evdev.h" >+ > #include <sys/param.h> > #include <sys/systm.h> > #include <sys/kernel.h> >@@ -56,6 +58,11 @@ __FBSDID("$FreeBSD$"); > #define USB_DEBUG_VAR wsp_debug > #include <dev/usb/usb_debug.h> > >+#ifdef EVDEV_SUPPORT >+#include <dev/evdev/input.h> >+#include <dev/evdev/evdev.h> >+#endif >+ > #include <sys/mouse.h> > > #define WSP_DRIVER_NAME "wsp" >@@ -226,9 +233,14 @@ struct tp_finger { > } __packed; > > /* trackpad finger data size, empirically at least ten fingers */ >+#ifdef EVDEV_SUPPORT >+#define MAX_FINGERS MAX_MT_SLOTS >+#else > #define MAX_FINGERS 16 >+#endif > #define SIZEOF_FINGER sizeof(struct tp_finger) > #define SIZEOF_ALL_FINGERS (MAX_FINGERS * SIZEOF_FINGER) >+#define MAX_FINGER_ORIENTATION 16384 > > #if (WSP_BUFFER_MAX < ((MAX_FINGERS * FSIZE_TYPE4) + FINGER_TYPE4)) > #error "WSP_BUFFER_MAX is too small" >@@ -251,6 +263,13 @@ enum { > WSP_FLAG_MAX, > }; > >+/* device-specific parameters */ >+struct wsp_param { >+ int snratio; /* signal-to-noise ratio */ >+ int min; /* device minimum reading */ >+ int max; /* device maximum reading */ >+}; >+ > /* device-specific configuration */ > struct wsp_dev_params { > uint8_t caps; /* device capability bitmask */ >@@ -266,8 +285,19 @@ struct wsp_dev_params { > uint8_t um_switch_idx; /* usb control message mode switch index */ > uint8_t um_switch_on; /* usb control message mode switch on */ > uint8_t um_switch_off; /* usb control message mode switch off */ >+ struct wsp_param p; /* finger pressure limits */ >+ struct wsp_param w; /* finger width limits */ >+ struct wsp_param x; /* horizontal limits */ >+ struct wsp_param y; /* vertical limits */ >+ struct wsp_param o; /* orientation limits */ > }; > >+/* logical signal quality */ >+#define SN_PRESSURE 45 /* pressure signal-to-noise ratio */ >+#define SN_WIDTH 25 /* width signal-to-noise ratio */ >+#define SN_COORD 250 /* coordinate signal-to-noise ratio */ >+#define SN_ORIENT 10 /* orientation signal-to-noise ratio */ >+ > static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > [WSP_FLAG_WELLSPRING1] = { > .caps = 0, >@@ -283,6 +313,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 256 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4824, 5342 }, >+ .y = { SN_COORD, -172, 5820 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING2] = { > .caps = 0, >@@ -298,6 +334,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 256 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4824, 4824 }, >+ .y = { SN_COORD, -172, 4290 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING3] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -313,6 +355,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4460, 5166 }, >+ .y = { SN_COORD, -75, 6700 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING4] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -328,6 +376,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4620, 5140 }, >+ .y = { SN_COORD, -150, 6600 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING4A] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -343,6 +397,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4616, 5112 }, >+ .y = { SN_COORD, -142, 5234 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING5] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -358,6 +418,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4415, 5050 }, >+ .y = { SN_COORD, -55, 6680 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING6] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -373,6 +439,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4620, 5140 }, >+ .y = { SN_COORD, -150, 6600 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING5A] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -388,6 +460,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4750, 5280 }, >+ .y = { SN_COORD, -150, 6730 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING6A] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -402,6 +480,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4620, 5140 }, >+ .y = { SN_COORD, -150, 6600 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING7] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -417,6 +501,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4750, 5280 }, >+ .y = { SN_COORD, -150, 6730 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING7A] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -432,6 +522,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4750, 5280 }, >+ .y = { SN_COORD, -150, 6730 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING8] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -447,6 +543,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 0, > .um_switch_on = 0x01, > .um_switch_off = 0x08, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4620, 5140 }, >+ .y = { SN_COORD, -150, 6600 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > [WSP_FLAG_WELLSPRING9] = { > .caps = HAS_INTEGRATED_BUTTON, >@@ -462,6 +564,12 @@ static const struct wsp_dev_params wsp_dev_params[WSP_FLAG_MAX] = { > .um_switch_idx = 1, > .um_switch_on = 0x01, > .um_switch_off = 0x00, >+ .p = { SN_PRESSURE, 0, 300 }, >+ .w = { SN_WIDTH, 0, 2048 }, >+ .x = { SN_COORD, -4828, 5345 }, >+ .y = { SN_COORD, -203, 6803 }, >+ .o = { SN_ORIENT, >+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }, > }, > }; > #define WSP_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } >@@ -550,12 +658,17 @@ struct wsp_softc { > > const struct wsp_dev_params *sc_params; /* device configuration */ > >+#ifdef EVDEV_SUPPORT >+ struct evdev_dev *sc_evdev; >+#endif > mousehw_t sc_hw; > mousemode_t sc_mode; > u_int sc_pollrate; > mousestatus_t sc_status; > u_int sc_state; >-#define WSP_ENABLED 0x01 >+#define WSP_ENABLED 0x01 >+#define WSP_FIFO_STARTED 0x02 >+#define WSP_EVDEV_OPENED 0x04 > > struct tp_finger *index[MAX_FINGERS]; /* finger index data */ > int16_t pos_x[MAX_FINGERS]; /* position array */ >@@ -596,8 +709,8 @@ struct wsp_softc { > /* > * function prototypes > */ >-static usb_fifo_cmd_t wsp_start_read; >-static usb_fifo_cmd_t wsp_stop_read; >+static usb_fifo_cmd_t wsp_fifo_start_read; >+static usb_fifo_cmd_t wsp_fifo_stop_read; > static usb_fifo_open_t wsp_open; > static usb_fifo_close_t wsp_close; > static usb_fifo_ioctl_t wsp_ioctl; >@@ -606,11 +719,20 @@ static struct usb_fifo_methods wsp_fifo_methods = { > .f_open = &wsp_open, > .f_close = &wsp_close, > .f_ioctl = &wsp_ioctl, >- .f_start_read = &wsp_start_read, >- .f_stop_read = &wsp_stop_read, >+ .f_start_read = &wsp_fifo_start_read, >+ .f_stop_read = &wsp_fifo_stop_read, > .basename[0] = WSP_DRIVER_NAME, > }; > >+#ifdef EVDEV_SUPPORT >+static evdev_open_t wsp_ev_open; >+static evdev_close_t wsp_ev_close; >+static const struct evdev_methods wsp_evdev_methods = { >+ .ev_open = &wsp_ev_open, >+ .ev_close = &wsp_ev_close, >+}; >+#endif >+ > /* device initialization and shutdown */ > static int wsp_enable(struct wsp_softc *sc); > static void wsp_disable(struct wsp_softc *sc); >@@ -816,6 +938,54 @@ wsp_attach(device_t dev) > sc->sc_touch = WSP_UNTOUCH; > sc->scr_mode = WSP_SCR_NONE; > >+#ifdef EVDEV_SUPPORT >+ sc->sc_evdev = evdev_alloc(); >+ evdev_set_name(sc->sc_evdev, device_get_desc(dev)); >+ evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev)); >+ evdev_set_id(sc->sc_evdev, BUS_USB, uaa->info.idVendor, >+ uaa->info.idProduct, 0); >+ evdev_set_serial(sc->sc_evdev, usb_get_serial(uaa->device)); >+ evdev_set_methods(sc->sc_evdev, sc, &wsp_evdev_methods); >+ evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER); >+ evdev_support_event(sc->sc_evdev, EV_SYN); >+ evdev_support_event(sc->sc_evdev, EV_ABS); >+ evdev_support_event(sc->sc_evdev, EV_KEY); >+ >+#define WSP_SUPPORT_ABS(evdev, code, param) \ >+ evdev_support_abs((evdev), (code), (param).min, (param).max, \ >+ ((param).max - (param).min) / (param).snratio, 0, 0); >+ >+ /* finger position */ >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_POSITION_X, sc->sc_params->x); >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_POSITION_Y, sc->sc_params->y); >+ /* finger pressure */ >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_PRESSURE, sc->sc_params->p); >+ /* finger touch area */ >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_TOUCH_MAJOR, sc->sc_params->w); >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_TOUCH_MINOR, sc->sc_params->w); >+ /* finger approach area */ >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_WIDTH_MAJOR, sc->sc_params->w); >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_WIDTH_MINOR, sc->sc_params->w); >+ /* finger orientation */ >+ WSP_SUPPORT_ABS(sc->sc_evdev, ABS_MT_ORIENTATION, sc->sc_params->o); >+ /* button properties */ >+ evdev_support_key(sc->sc_evdev, BTN_LEFT); >+ if ((sc->sc_params->caps & HAS_INTEGRATED_BUTTON) != 0) >+ evdev_support_prop(sc->sc_evdev, INPUT_PROP_BUTTONPAD); >+ /* Enable automatic touch assignment for type B MT protocol */ >+ evdev_support_abs(sc->sc_evdev, ABS_MT_SLOT, >+ 0, MAX_FINGERS - 1, 0, 0, 0); >+ evdev_support_abs(sc->sc_evdev, ABS_MT_TRACKING_ID, >+ 0, MAX_FINGERS - 1, 0, 0, 0); >+ evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_TRACK); >+ /* Synaptics compatibility events */ >+ evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_STCOMPAT); >+ >+ err = evdev_register(sc->sc_evdev); >+ if (err) >+ goto detach; >+#endif >+ > return (0); > > detach: >@@ -837,6 +1007,10 @@ wsp_detach(device_t dev) > > usb_fifo_detach(&sc->sc_fifo); > >+#ifdef EVDEV_SUPPORT >+ evdev_free(sc->sc_evdev); >+#endif >+ > usbd_transfer_unsetup(sc->sc_xfer, WSP_N_TRANSFER); > > mtx_destroy(&sc->sc_mutex); >@@ -929,8 +1103,37 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) > sc->pos_x[i] = f->abs_x; > sc->pos_y[i] = -f->abs_y; > sc->index[i] = f; >+#ifdef EVDEV_SUPPORT >+ if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) { >+ union evdev_mt_slot slot_data = { >+ .id = i, >+ .x = f->abs_x, >+ .y = params->y.max + params->y.min - f->abs_y, >+ .p = f->pressure, >+ .maj = f->touch_major << 1, >+ .min = f->touch_minor << 1, >+ .w_maj = f->tool_major << 1, >+ .w_min = f->tool_minor << 1, >+ .ori = params->o.max - f->orientation, >+ }; >+ evdev_mt_push_slot(sc->sc_evdev, i, &slot_data); >+ } >+#endif > } > >+#ifdef EVDEV_SUPPORT >+ if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) { >+ /* >+ * As EVDEV_FLAG_MT_AUTOREL is not set we should call >+ * evdev_mt_push_autorel explicitly when no touches is >+ * reported. >+ */ >+ if (ntouch == 0) >+ evdev_mt_push_autorel(sc->sc_evdev); >+ evdev_push_key(sc->sc_evdev, BTN_LEFT, ibt); >+ evdev_sync(sc->sc_evdev); >+ } >+#endif > sc->sc_status.flags &= ~MOUSE_POSCHANGED; > sc->sc_status.flags &= ~MOUSE_STDBUTTONSCHANGED; > sc->sc_status.obutton = sc->sc_status.button; >@@ -1235,9 +1438,8 @@ wsp_reset_buf(struct wsp_softc *sc) > } > > static void >-wsp_start_read(struct usb_fifo *fifo) >+wsp_start_read(struct wsp_softc *sc) > { >- struct wsp_softc *sc = usb_fifo_softc(fifo); > int rate; > > /* Check if we should override the default polling interval */ >@@ -1258,10 +1460,8 @@ wsp_start_read(struct usb_fifo *fifo) > } > > static void >-wsp_stop_read(struct usb_fifo *fifo) >+wsp_stop_read(struct wsp_softc *sc) > { >- struct wsp_softc *sc = usb_fifo_softc(fifo); >- > usbd_transfer_stop(sc->sc_xfer[WSP_INTR_DT]); > } > >@@ -1301,6 +1501,56 @@ wsp_close(struct usb_fifo *fifo, int fflags) > } > } > >+static void >+wsp_fifo_start_read(struct usb_fifo *fifo) >+{ >+ struct wsp_softc *sc = usb_fifo_softc(fifo); >+ >+ if ((sc->sc_state & WSP_EVDEV_OPENED) == 0) >+ wsp_start_read(sc); >+ sc->sc_state |= WSP_FIFO_STARTED; >+} >+ >+static void >+wsp_fifo_stop_read(struct usb_fifo *fifo) >+{ >+ struct wsp_softc *sc = usb_fifo_softc(fifo); >+ >+ sc->sc_state &= ~WSP_FIFO_STARTED; >+ if ((sc->sc_state & WSP_EVDEV_OPENED) == 0) >+ wsp_stop_read(sc); >+} >+ >+#ifdef EVDEV_SUPPORT >+static int >+wsp_ev_open(struct evdev_dev *evdev) >+{ >+ struct wsp_softc *sc = evdev_get_softc(evdev); >+ >+ mtx_lock(&sc->sc_mutex); >+ if ((sc->sc_state & WSP_FIFO_STARTED) == 0) >+ wsp_start_read(sc); >+ sc->sc_state |= WSP_EVDEV_OPENED; >+ mtx_unlock(&sc->sc_mutex); >+ >+ return (0); >+} >+ >+static int >+wsp_ev_close(struct evdev_dev *evdev) >+{ >+ struct wsp_softc *sc = evdev_get_softc(evdev); >+ >+ mtx_lock(&sc->sc_mutex); >+ sc->sc_state &= ~WSP_EVDEV_OPENED; >+ if ((sc->sc_state & WSP_FIFO_STARTED) == 0) >+ wsp_stop_read(sc); >+ mtx_unlock(&sc->sc_mutex); >+ >+ return (0); >+} >+#endif >+ > int > wsp_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags) > { >@@ -1412,5 +1662,8 @@ static devclass_t wsp_devclass; > DRIVER_MODULE(wsp, uhub, wsp_driver, wsp_devclass, NULL, 0); > MODULE_DEPEND(wsp, usb, 1, 1, 1); > MODULE_DEPEND(wsp, hid, 1, 1, 1); >+#ifdef EVDEV_SUPPORT >+MODULE_DEPEND(wsp, evdev, 1, 1, 1); >+#endif > MODULE_VERSION(wsp, 1); > USB_PNP_HOST_INFO(wsp_devs); >diff --git a/sys/modules/usb/wsp/Makefile b/sys/modules/usb/wsp/Makefile >index a5215c0150f..73a289a0954 100644 >--- a/sys/modules/usb/wsp/Makefile >+++ b/sys/modules/usb/wsp/Makefile >@@ -30,7 +30,7 @@ S= ${SRCTOP}/sys > .PATH: $S/dev/usb/input > > KMOD= wsp >-SRCS= opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h vnode_if.h usbdevs.h \ >- wsp.c >+SRCS= opt_bus.h opt_evdev.h opt_usb.h device_if.h bus_if.h usb_if.h \ >+ vnode_if.h usbdevs.h wsp.c > > .include <bsd.kmod.mk>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 252236
:
222890
|
223176
|
223223
|
223229
|
223231
|
223232
|
223276
|
223277
|
223347
|
223450
|
223683
|
224948
|
224949
|
224968