Page MenuHomeFreeBSD

D31653.id94097.diff
No OneTemporary

D31653.id94097.diff

Index: sys/dev/evdev/cdev.c
===================================================================
--- sys/dev/evdev/cdev.c
+++ sys/dev/evdev/cdev.c
@@ -621,7 +621,7 @@
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):
Index: sys/dev/evdev/evdev.h
===================================================================
--- sys/dev/evdev/evdev.h
+++ sys/dev/evdev/evdev.h
@@ -90,6 +90,8 @@
* 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_KEEPID 0x04 /* Do not reassign tracking ID */
+#define EVDEV_FLAG_MT_TRACK 0x05 /* Assign touch to slot by evdev */
#define EVDEV_FLAG_MAX 0x1F
#define EVDEV_FLAG_CNT (EVDEV_FLAG_MAX + 1)
@@ -102,6 +104,29 @@
evdev_keycode_t *ev_set_keycode;
};
+union evdev_mt_slot {
+ int32_t val[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, val[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 +156,19 @@
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);
+void evdev_mt_match_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 +177,8 @@
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
Index: sys/dev/evdev/evdev.c
===================================================================
--- sys/dev/evdev/evdev.c
+++ sys/dev/evdev/evdev.c
@@ -306,8 +306,9 @@
}
}
- /* Initialize multitouch protocol type B states */
- if (bit_test(evdev->ev_abs_flags, ABS_MT_SLOT))
+ /* Initialize multitouch protocol type B states or A to B converter */
+ if (bit_test(evdev->ev_abs_flags, ABS_MT_SLOT) ||
+ bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK))
evdev_mt_init(evdev);
/* Estimate maximum report size */
@@ -710,15 +711,23 @@
break;
case EV_ABS:
- fuzz = evdev->ev_absinfo[code].fuzz;
- if (fuzz == 0 || code == ABS_MT_SLOT)
+ if (code == ABS_MT_SLOT)
break;
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);
- else /* Pass MT protocol type A events as is */
+ else if (!bit_test(evdev->ev_abs_flags, ABS_MT_SLOT))
+ /* Pass MT protocol type A events as is */
+ break;
+ else if (code == ABS_MT_TRACKING_ID) {
+ *value = evdev_mt_reassign_id(evdev,
+ evdev_mt_get_last_slot(evdev), *value);
+ break;
+ } else
+ old_value = evdev_mt_get_value(evdev,
+ evdev_mt_get_last_slot(evdev), code);
+
+ fuzz = evdev->ev_absinfo[code].fuzz;
+ if (fuzz == 0)
break;
abs_change = abs(*value - old_value);
@@ -797,7 +806,7 @@
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:
@@ -805,11 +814,11 @@
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;
@@ -885,6 +894,7 @@
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:
@@ -948,15 +958,16 @@
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);
Index: sys/dev/evdev/evdev_mt.c
===================================================================
--- sys/dev/evdev/evdev_mt.c
+++ 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,92 @@
#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,
-};
+typedef u_int slotset_t;
-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 },
-};
+_Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big");
+
+#define FOREACHBIT(v, i) \
+ for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 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;
+ uint16_t tracking_id;
+ int32_t tracking_ids[MAX_MT_SLOTS];
+ bool type_a;
+ u_int mtst_events;
+ /* the set of slots with active touches */
+ slotset_t touches;
+ /* the set of slots with unsynchronized state */
+ slotset_t frame;
+ /* the set of slots to match with active touches */
+ slotset_t match_frame;
+ int match_slot;
+ union evdev_mt_slot *match_slots;
+ int *matrix;
+ union evdev_mt_slot slots[];
};
+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 *);
+
+static inline int
+ffc_slot(struct evdev_dev *evdev, slotset_t slots)
+{
+ return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1);
+}
+
void
evdev_mt_init(struct evdev_dev *evdev)
{
- int32_t slot, slots;
+ struct evdev_mt *mt;
+ size_t size = offsetof(struct evdev_mt, slots);
+ int slot, slots;
+ bool type_a;
+
+ type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
+ if (type_a) {
+ /* Add events produced by MT type A to type B converter */
+ evdev_support_abs(evdev,
+ ABS_MT_SLOT, 0, MAX_MT_SLOTS - 1, 0, 0, 0);
+ evdev_support_abs(evdev,
+ ABS_MT_TRACKING_ID, -1, MAX_MT_SLOTS - 1, 0, 0, 0);
+ }
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;
+ mt->type_a = type_a;
- /* Initialize multitouch protocol type B states */
- for (slot = 0; slot < slots; slot++) {
- /*
- * .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
- */
- 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_flags, EVDEV_FLAG_MT_TRACK)) {
+ mt->match_slots = 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_KEEPID))
+ evdev_support_abs(evdev,
+ ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0);
if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
evdev_support_mt_compat(evdev);
}
@@ -97,155 +150,497 @@
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;
+ bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
+
+ EVDEV_LOCK_ASSERT(evdev);
+ MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)));
+ MPASS(!type_a || state != NULL);
+
+ if (!type_a) {
+ 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->val[ABS_MT_INDEX(i)]);
+ if (type_a)
+ evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
+}
+
+int
+evdev_mt_push_slot(struct evdev_dev *evdev, int slot,
+ union evdev_mt_slot *state)
+{
+ struct evdev_mt *mt = evdev->ev_mt;
+ bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
+
+ if ((type_a || (mt != NULL && mt->type_a)) && state == NULL)
+ return (EINVAL);
+ if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev)))
+ return (EINVAL);
+
+ EVDEV_ENTER(evdev);
+ if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK) && mt->type_a) {
+ mt->match_slots[mt->match_slot] = *state;
+ evdev_mt_record_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
+ } else 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);
+}
- return (evdev->ev_mt->ev_mt_last_reported_slot);
+/*
+ * 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 tracking IDs to the points in the pt array. The tracking ID
+ * 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.
+ * Set tracking id to -1 for unassigned (new) points.
+ */
void
-evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot)
+evdev_mt_match_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;
+
+ EVDEV_LOCK_ASSERT(evdev);
+ MPASS(mt->matrix != NULL);
+ MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
+
+ if (size == 0)
+ return;
- evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count;
- evdev->ev_mt->ev_mt_last_reported_slot = slot;
+ p = mt->matrix;
+ num_touches = bitcount(mt->touches);
+ if (num_touches >= size) {
+ FOREACHBIT(mt->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(mt->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)
+ pt[i].id = -1;
+
+ p = (n == size ? r2c : c2r);
+ FOREACHBIT(mt->touches, slot)
+ if ((i = *p++) >= 0)
+ pt[i].id = mt->tracking_ids[slot];
}
-inline int32_t
-evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code)
+static void
+evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size)
{
+ struct evdev_mt *mt = evdev->ev_mt;
+ union evdev_mt_slot *slot;
- return (evdev->ev_mt->
- ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]);
+ EVDEV_LOCK_ASSERT(evdev);
+ MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
+
+ /*
+ * While MT-matching assign tracking IDs of new contacts to be equal
+ * to a slot number to make things simpler.
+ */
+ for (slot = pt; slot < pt + size; slot++) {
+ if (slot->id < 0)
+ slot->id = ffc_slot(evdev, mt->touches | mt->frame);
+ if (slot->id >= 0)
+ evdev_mt_send_slot(evdev, slot->id, slot);
+ }
}
-inline void
-evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code,
+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_send_frame(evdev, pt, size);
+ EVDEV_EXIT(evdev);
+
+ return (0);
+}
+
+bool
+evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
int32_t value)
{
+ struct evdev_mt *mt = evdev->ev_mt;
+
+ 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].
+ val[ABS_MT_INDEX(code)] = value;
+ return (true);
+ }
+ break;
+ default:
+ break;
+ }
- evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] =
- value;
+ return (false);
}
-int32_t
-evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
+static void
+evdev_mt_replay_events(struct evdev_dev *evdev)
{
- int32_t tr_id, slot, free_slot = -1;
+ struct evdev_mt *mt = evdev->ev_mt;
+ int slot, size = 0;
- 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);
+
+ FOREACHBIT(mt->match_frame, slot) {
+ if (slot != size)
+ mt->match_slots[size] = mt->match_slots[slot];
+ size++;
}
+ evdev_mt_match_frame(evdev, mt->match_slots, size);
+ evdev_mt_send_frame(evdev, mt->match_slots, size);
+ mt->match_slot = 0;
+ mt->match_frame = 0;
+}
+
+union evdev_mt_slot *
+evdev_mt_get_match_slots(struct evdev_dev *evdev)
+{
+ return (evdev->ev_mt->match_slots);
+}
- return (free_slot);
+int
+evdev_mt_get_last_slot(struct evdev_dev *evdev)
+{
+ return (evdev->ev_mt->last_reported_slot);
}
void
-evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers)
+evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot)
{
- int32_t i;
+ struct evdev_mt *mt = evdev->ev_mt;
+
+ MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
- for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++)
- evdev_support_key(evdev, evdev_fngmap[i]);
+ mt->frame |= 1U << slot;
+ mt->last_reported_slot = slot;
}
-void
-evdev_support_mt_compat(struct evdev_dev *evdev)
+int32_t
+evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code)
{
- int32_t i;
+ struct evdev_mt *mt = evdev->ev_mt;
- if (evdev->ev_absinfo == NULL)
- return;
+ MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
- evdev_support_event(evdev, EV_KEY);
- evdev_support_key(evdev, BTN_TOUCH);
+ return (mt->slots[slot].val[ABS_MT_INDEX(code)]);
+}
- /* 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);
+void
+evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code,
+ int32_t value)
+{
+ struct evdev_mt *mt = evdev->ev_mt;
- /* 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);
+ 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].val[ABS_MT_INDEX(code)] = value;
}
-static int32_t
-evdev_count_fingers(struct evdev_dev *evdev)
+int
+evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
{
- int32_t nfingers = 0, i;
+ struct evdev_mt *mt = evdev->ev_mt;
+ int slot;
+
+ KASSERT(!mt->type_a, ("Not a MT type B protocol"));
- for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
- if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
- nfingers++;
+ /*
+ * 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))
+ return (ffc_slot(evdev, mt->match_frame));
- return (nfingers);
+ FOREACHBIT(mt->touches, slot)
+ if (mt->tracking_ids[slot] == tracking_id)
+ return (slot);
+ /*
+ * Do not allow allocation of new slot in a place of just
+ * released one within the same report.
+ */
+ return (ffc_slot(evdev, mt->touches | mt->frame));
}
-static void
-evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers)
+int32_t
+evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id)
{
- int32_t i;
+ struct evdev_mt *mt = evdev->ev_mt;
+ int32_t nid;
- EVDEV_LOCK_ASSERT(evdev);
+ if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) {
+ mt->tracking_ids[slot] = id;
+ return (id);
+ }
+
+ nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID);
+ if (nid != -1) {
+ KASSERT(id == mt->tracking_ids[slot],
+ ("MT-slot tracking id has changed"));
+ return (nid);
+ }
- if (nfingers > nitems(evdev_fngmap))
- nfingers = nitems(evdev_fngmap);
+ mt->tracking_ids[slot] = id;
+again:
+ nid = mt->tracking_id++;
+ FOREACHBIT(mt->touches, slot)
+ if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid)
+ goto again;
- for (i = 0; i < nitems(evdev_fngmap); i++)
- evdev_send_event(evdev, EV_KEY, evdev_fngmap[i],
- nfingers == i + 1);
+ return (nid);
+}
+
+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 +655,27 @@
{
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);
+ KASSERT(mt->match_frame == 0, ("Unmatched events exist"));
- 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);
}
Index: sys/dev/evdev/evdev_private.h
===================================================================
--- sys/dev/evdev/evdev_private.h
+++ sys/dev/evdev/evdev_private.h
@@ -279,14 +279,16 @@
/* 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);
+int32_t evdev_mt_reassign_id(struct evdev_dev *, int, 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 */
Index: sys/dev/evdev/evdev_utils.c
===================================================================
--- sys/dev/evdev/evdev_utils.c
+++ 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 @@
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_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);
+}
Index: sys/dev/evdev/uinput.c
===================================================================
--- sys/dev/evdev/uinput.c
+++ sys/dev/evdev/uinput.c
@@ -495,6 +495,7 @@
evdev_set_methods(state->ucs_evdev, state, &uinput_ev_methods);
evdev_set_flag(state->ucs_evdev, EVDEV_FLAG_SOFTREPEAT);
+ evdev_set_flag(state->ucs_evdev, EVDEV_FLAG_MT_KEEPID);
ret = evdev_register(state->ucs_evdev);
if (ret == 0)
state->ucs_state = UINPUT_RUNNING;
Index: sys/dev/usb/input/atp.c
===================================================================
--- sys/dev/usb/input/atp.c
+++ sys/dev/usb/input/atp.c
@@ -2175,11 +2175,11 @@
if ((usbd_lookup_id_by_uaa(fg_devs, sizeof(fg_devs), uaa)) == 0)
return ((uaa->info.bInterfaceProtocol == UIPROTO_MOUSE) ?
- 0 : ENXIO);
+ BUS_PROBE_DEFAULT : ENXIO);
if ((usbd_lookup_id_by_uaa(wsp_devs, sizeof(wsp_devs), uaa)) == 0)
if (uaa->info.bIfaceIndex == WELLSPRING_INTERFACE_INDEX)
- return (0);
+ return (BUS_PROBE_DEFAULT);
return (ENXIO);
}
Index: sys/dev/usb/input/wsp.c
===================================================================
--- sys/dev/usb/input/wsp.c
+++ 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 @@
#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"
@@ -169,7 +176,8 @@
TYPE1, /* plain trackpad */
TYPE2, /* button integrated in trackpad */
TYPE3, /* additional header fields since June 2013 */
- TYPE4 /* additional header field for pressure data */
+ TYPE4, /* additional header field for pressure data */
+ TYPE_CNT
};
/* trackpad finger data offsets, le16-aligned */
@@ -192,6 +200,67 @@
#define FSIZE_TYPE3 (14 * 2)
#define FSIZE_TYPE4 (15 * 2)
+struct wsp_tp {
+ uint8_t caps; /* device capability bitmask */
+ uint8_t button; /* offset to button data */
+ uint8_t offset; /* offset to trackpad finger data */
+ uint8_t fsize; /* bytes in single finger block */
+ uint8_t delta; /* offset from header to finger struct */
+ uint8_t iface_index;
+ uint8_t um_size; /* usb control message length */
+ uint8_t um_req_idx; /* usb control message index */
+ 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 */
+} const static wsp_tp[TYPE_CNT] = {
+ [TYPE1] = {
+ .caps = 0,
+ .button = 0,
+ .offset = FINGER_TYPE1,
+ .fsize = FSIZE_TYPE1,
+ .delta = 0,
+ .iface_index = 0,
+ .um_size = 8,
+ .um_req_idx = 0x00,
+ .um_switch_idx = 0,
+ .um_switch_on = 0x01,
+ .um_switch_off = 0x08,
+ },
+ [TYPE2] = {
+ .caps = HAS_INTEGRATED_BUTTON,
+ .button = BUTTON_TYPE2,
+ .offset = FINGER_TYPE2,
+ .fsize = FSIZE_TYPE2,
+ .delta = 0,
+ .iface_index = 0,
+ .um_size = 8,
+ .um_req_idx = 0x00,
+ .um_switch_idx = 0,
+ .um_switch_on = 0x01,
+ .um_switch_off = 0x08,
+ },
+ [TYPE3] = {
+ .caps = HAS_INTEGRATED_BUTTON,
+ .button = BUTTON_TYPE3,
+ .offset = FINGER_TYPE3,
+ .fsize = FSIZE_TYPE3,
+ .delta = 0,
+ },
+ [TYPE4] = {
+ .caps = HAS_INTEGRATED_BUTTON,
+ .button = BUTTON_TYPE4,
+ .offset = FINGER_TYPE4,
+ .fsize = FSIZE_TYPE4,
+ .delta = 2,
+ .iface_index = 2,
+ .um_size = 2,
+ .um_req_idx = 0x02,
+ .um_switch_idx = 1,
+ .um_switch_on = 0x01,
+ .um_switch_off = 0x00,
+ },
+};
+
/* trackpad finger header - little endian */
struct tp_header {
uint8_t flag;
@@ -226,9 +295,14 @@
} __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,217 +325,147 @@
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 */
+ int size; /* physical size, mm */
+};
+
/* device-specific configuration */
struct wsp_dev_params {
- uint8_t caps; /* device capability bitmask */
- uint8_t tp_type; /* type of trackpad interface */
- uint8_t tp_button; /* offset to button data */
- uint8_t tp_offset; /* offset to trackpad finger data */
- uint8_t tp_fsize; /* bytes in single finger block */
- uint8_t tp_delta; /* offset from header to finger struct */
- uint8_t iface_index;
- uint8_t um_size; /* usb control message length */
- uint8_t um_req_val; /* usb control message value */
- uint8_t um_req_idx; /* usb control message index */
- 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 */
+ const struct wsp_tp* tp;
+ 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,
- .tp_type = TYPE1,
- .tp_button = 0,
- .tp_offset = FINGER_TYPE1,
- .tp_fsize = FSIZE_TYPE1,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE1,
+ .p = { SN_PRESSURE, 0, 256, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4824, 5342, 105 },
+ .y = { SN_COORD, -172, 5820, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING2] = {
- .caps = 0,
- .tp_type = TYPE1,
- .tp_button = 0,
- .tp_offset = FINGER_TYPE1,
- .tp_fsize = FSIZE_TYPE1,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE1,
+ .p = { SN_PRESSURE, 0, 256, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4824, 4824, 105 },
+ .y = { SN_COORD, -172, 4290, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING3] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4460, 5166, 105 },
+ .y = { SN_COORD, -75, 6700, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING4] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4620, 5140, 105 },
+ .y = { SN_COORD, -150, 6600, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING4A] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4616, 5112, 105 },
+ .y = { SN_COORD, -142, 5234, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING5] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4415, 5050, 105 },
+ .y = { SN_COORD, -55, 6680, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING6] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4620, 5140, 105 },
+ .y = { SN_COORD, -150, 6600, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING5A] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4750, 5280, 105 },
+ .y = { SN_COORD, -150, 6730, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING6A] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4620, 5140, 105 },
+ .y = { SN_COORD, -150, 6600, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING7] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4750, 5280, 105 },
+ .y = { SN_COORD, -150, 6730, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING7A] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE2,
- .tp_button = BUTTON_TYPE2,
- .tp_offset = FINGER_TYPE2,
- .tp_fsize = FSIZE_TYPE2,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE2,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4750, 5280, 105 },
+ .y = { SN_COORD, -150, 6730, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING8] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE3,
- .tp_button = BUTTON_TYPE3,
- .tp_offset = FINGER_TYPE3,
- .tp_fsize = FSIZE_TYPE3,
- .tp_delta = 0,
- .iface_index = 0,
- .um_size = 8,
- .um_req_val = 0x03,
- .um_req_idx = 0x00,
- .um_switch_idx = 0,
- .um_switch_on = 0x01,
- .um_switch_off = 0x08,
+ .tp = wsp_tp + TYPE3,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4620, 5140, 105 },
+ .y = { SN_COORD, -150, 6600, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
[WSP_FLAG_WELLSPRING9] = {
- .caps = HAS_INTEGRATED_BUTTON,
- .tp_type = TYPE4,
- .tp_button = BUTTON_TYPE4,
- .tp_offset = FINGER_TYPE4,
- .tp_fsize = FSIZE_TYPE4,
- .tp_delta = 2,
- .iface_index = 2,
- .um_size = 2,
- .um_req_val = 0x03,
- .um_req_idx = 0x02,
- .um_switch_idx = 1,
- .um_switch_on = 0x01,
- .um_switch_off = 0x00,
+ .tp = wsp_tp + TYPE4,
+ .p = { SN_PRESSURE, 0, 300, 0 },
+ .w = { SN_WIDTH, 0, 2048, 0 },
+ .x = { SN_COORD, -4828, 5345, 105 },
+ .y = { SN_COORD, -203, 6803, 75 },
+ .o = { SN_ORIENT,
+ -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 0 },
},
};
#define WSP_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
@@ -550,12 +554,17 @@
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;
+ int sc_fflags;
u_int sc_state;
-#define WSP_ENABLED 0x01
+#define WSP_ENABLED 0x01
+#define WSP_EVDEV_OPENED 0x02
struct tp_finger *index[MAX_FINGERS]; /* finger index data */
int16_t pos_x[MAX_FINGERS]; /* position array */
@@ -596,8 +605,8 @@
/*
* 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 +615,20 @@
.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);
@@ -647,12 +665,12 @@
usb_error_t err;
/* Type 3 does not require a mode switch */
- if (params->tp_type == TYPE3)
+ if (params->tp == wsp_tp + TYPE3)
return 0;
err = usbd_req_get_report(sc->sc_usb_device, NULL,
- mode_bytes, params->um_size, params->iface_index,
- params->um_req_val, params->um_req_idx);
+ mode_bytes, params->tp->um_size, params->tp->iface_index,
+ UHID_FEATURE_REPORT, params->tp->um_req_idx);
if (err != USB_ERR_NORMAL_COMPLETION) {
DPRINTF("Failed to read device mode (%d)\n", err);
@@ -667,12 +685,12 @@
*/
pause("WHW", hz / 4);
- mode_bytes[params->um_switch_idx] =
- on ? params->um_switch_on : params->um_switch_off;
+ mode_bytes[params->tp->um_switch_idx] =
+ on ? params->tp->um_switch_on : params->tp->um_switch_off;
return (usbd_req_set_report(sc->sc_usb_device, NULL,
- mode_bytes, params->um_size, params->iface_index,
- params->um_req_val, params->um_req_idx));
+ mode_bytes, params->tp->um_size, params->tp->iface_index,
+ UHID_FEATURE_REPORT, params->tp->um_req_idx));
}
static int
@@ -720,7 +738,10 @@
/* check if we are attaching to the first match */
if (uaa->info.bIfaceIndex != i)
return (ENXIO);
- return (usbd_lookup_id_by_uaa(wsp_devs, sizeof(wsp_devs), uaa));
+ if (usbd_lookup_id_by_uaa(wsp_devs, sizeof(wsp_devs), uaa) != 0)
+ return (ENXIO);
+
+ return (BUS_PROBE_DEFAULT);
}
static int
@@ -816,6 +837,56 @@
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, \
+ (param).size != 0 ? ((param).max - (param).min) / (param).size : 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->tp->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,
+ -1, MAX_FINGERS - 1, 0, 0, 0);
+ evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_TRACK);
+ evdev_set_flag(sc->sc_evdev, EVDEV_FLAG_MT_AUTOREL);
+ /* 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 +908,10 @@
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);
@@ -863,6 +938,9 @@
int rdz = 0;
int len;
int i;
+#ifdef EVDEV_SUPPORT
+ int slot = 0;
+#endif
wsp_runing_rangecheck(&tun);
@@ -878,8 +956,8 @@
pc = usbd_xfer_get_frame(xfer, 0);
usbd_copy_out(pc, 0, sc->tp_data, len);
- if ((len < params->tp_offset + params->tp_fsize) ||
- ((len - params->tp_offset) % params->tp_fsize) != 0) {
+ if ((len < params->tp->offset + params->tp->fsize) ||
+ ((len - params->tp->offset) % params->tp->fsize) != 0) {
DPRINTFN(WSP_LLEVEL_INFO, "Invalid length: %d, %x, %x\n",
len, sc->tp_data[0], sc->tp_data[1]);
goto tr_setup;
@@ -892,10 +970,12 @@
h = (struct tp_header *)(sc->tp_data);
- if (params->tp_type >= TYPE2) {
- ibt = sc->tp_data[params->tp_button];
- ntouch = sc->tp_data[params->tp_button - 1];
- }
+ if (params->tp != wsp_tp + TYPE1) {
+ ibt = sc->tp_data[params->tp->button];
+ ntouch = sc->tp_data[params->tp->button - 1];
+ } else
+ ntouch = (len - params->tp->offset) / params->tp->fsize;
+
/* range check */
if (ntouch < 0)
ntouch = 0;
@@ -903,7 +983,7 @@
ntouch = MAX_FINGERS;
for (i = 0; i != ntouch; i++) {
- f = (struct tp_finger *)(sc->tp_data + params->tp_offset + params->tp_delta + i * params->tp_fsize);
+ f = (struct tp_finger *)(sc->tp_data + params->tp->offset + params->tp->delta + i * params->tp->fsize);
/* swap endianness, if any */
if (le16toh(0x1234) != 0x1234) {
f->origin = le16toh((uint16_t)f->origin);
@@ -929,17 +1009,40 @@
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 && f->touch_major != 0) {
+ union evdev_mt_slot slot_data = {
+ .id = slot,
+ .x = f->abs_x,
+ .y = params->y.min + params->y.max - 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, slot, &slot_data);
+ slot++;
+ }
+#endif
}
+#ifdef EVDEV_SUPPORT
+ if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
+ 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;
sc->sc_status.button = 0;
if (ibt != 0) {
- if ((params->caps & HAS_INTEGRATED_BUTTON) && ntouch == 2)
+ if ((params->tp->caps & HAS_INTEGRATED_BUTTON) && ntouch == 2)
sc->sc_status.button |= MOUSE_BUTTON3DOWN;
- else if ((params->caps & HAS_INTEGRATED_BUTTON) && ntouch == 3)
+ else if ((params->tp->caps & HAS_INTEGRATED_BUTTON) && ntouch == 3)
sc->sc_status.button |= MOUSE_BUTTON2DOWN;
else
sc->sc_status.button |= MOUSE_BUTTON1DOWN;
@@ -986,7 +1089,7 @@
*/
switch (sc->ntaps) {
case 1:
- if (!(params->caps & HAS_INTEGRATED_BUTTON) || tun.enable_single_tap_clicks) {
+ if (!(params->tp->caps & HAS_INTEGRATED_BUTTON) || tun.enable_single_tap_clicks) {
wsp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON1DOWN);
DPRINTFN(WSP_LLEVEL_INFO, "LEFT CLICK!\n");
}
@@ -1235,9 +1338,8 @@
}
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,49 +1360,109 @@
}
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]);
}
static int
wsp_open(struct usb_fifo *fifo, int fflags)
{
- DPRINTFN(WSP_LLEVEL_INFO, "\n");
+ struct wsp_softc *sc = usb_fifo_softc(fifo);
+ int rc = 0;
- if (fflags & FREAD) {
- struct wsp_softc *sc = usb_fifo_softc(fifo);
- int rc;
+ DPRINTFN(WSP_LLEVEL_INFO, "\n");
- if (sc->sc_state & WSP_ENABLED)
- return (EBUSY);
+ if (sc->sc_fflags & fflags)
+ return (EBUSY);
+ if (fflags & FREAD) {
if (usb_fifo_alloc_buffer(fifo,
WSP_FIFO_BUF_SIZE, WSP_FIFO_QUEUE_MAXLEN)) {
return (ENOMEM);
}
- rc = wsp_enable(sc);
+#ifdef EVDEV_SUPPORT
+ if ((sc->sc_state & WSP_EVDEV_OPENED) == 0)
+#endif
+ rc = wsp_enable(sc);
if (rc != 0) {
usb_fifo_free_buffer(fifo);
return (rc);
}
}
+ sc->sc_fflags |= fflags & (FREAD | FWRITE);
return (0);
}
static void
wsp_close(struct usb_fifo *fifo, int fflags)
{
- if (fflags & FREAD) {
- struct wsp_softc *sc = usb_fifo_softc(fifo);
+ struct wsp_softc *sc = usb_fifo_softc(fifo);
- wsp_disable(sc);
+ if (fflags & FREAD) {
+#ifdef EVDEV_SUPPORT
+ if ((sc->sc_state & WSP_EVDEV_OPENED) == 0)
+#endif
+ wsp_disable(sc);
usb_fifo_free_buffer(fifo);
}
+
+ sc->sc_fflags &= ~(fflags & (FREAD | FWRITE));
}
+static void
+wsp_fifo_start_read(struct usb_fifo *fifo)
+{
+ struct wsp_softc *sc = usb_fifo_softc(fifo);
+
+ wsp_start_read(sc);
+}
+
+static void
+wsp_fifo_stop_read(struct usb_fifo *fifo)
+{
+ struct wsp_softc *sc = usb_fifo_softc(fifo);
+
+#ifdef EVDEV_SUPPORT
+ if ((sc->sc_state & WSP_EVDEV_OPENED) == 0)
+#endif
+ wsp_stop_read(sc);
+}
+
+#ifdef EVDEV_SUPPORT
+static int
+wsp_ev_open(struct evdev_dev *evdev)
+{
+ struct wsp_softc *sc = evdev_get_softc(evdev);
+ int rc = 0;
+
+ mtx_lock(&sc->sc_mutex);
+ if (sc->sc_fflags == 0)
+ rc = wsp_enable(sc);
+ if (rc == 0) {
+ wsp_start_read(sc);
+ sc->sc_state |= WSP_EVDEV_OPENED;
+ }
+ mtx_unlock(&sc->sc_mutex);
+
+ return (rc);
+}
+
+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_fflags == 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 +1574,8 @@
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);
Index: sys/modules/usb/wsp/Makefile
===================================================================
--- sys/modules/usb/wsp/Makefile
+++ sys/modules/usb/wsp/Makefile
@@ -30,7 +30,7 @@
.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>

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 27, 11:44 AM (15 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17817068
Default Alt Text
D31653.id94097.diff (56 KB)

Event Timeline