summaryrefslogtreecommitdiffstats
path: root/sys/dev/hid
diff options
context:
space:
mode:
authorbru <bru@openbsd.org>2017-10-08 10:13:42 +0000
committerbru <bru@openbsd.org>2017-10-08 10:13:42 +0000
commitb965ecea48d168755a7bf9a43ab45ae01fe2ff3c (patch)
tree8250a0da3b5e0a63fc9dda09e252d367bcc248aa /sys/dev/hid
parentEnable rkiic(4) and rkpmic(4) for Rockchip RK3288 boards. (diff)
downloadwireguard-openbsd-b965ecea48d168755a7bf9a43ab45ae01fe2ff3c.tar.xz
wireguard-openbsd-b965ecea48d168755a7bf9a43ab45ae01fe2ff3c.zip
Adapt hidmt to the MT interface of wsmouse, and add the compat-mode setup.
ok mpi@, jcs@
Diffstat (limited to 'sys/dev/hid')
-rw-r--r--sys/dev/hid/hidmt.c168
-rw-r--r--sys/dev/hid/hidmtvar.h6
2 files changed, 124 insertions, 50 deletions
diff --git a/sys/dev/hid/hidmt.c b/sys/dev/hid/hidmt.c
index bb7287a0046..3898547e0f9 100644
--- a/sys/dev/hid/hidmt.c
+++ b/sys/dev/hid/hidmt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hidmt.c,v 1.2 2016/03/30 23:34:12 bru Exp $ */
+/* $OpenBSD: hidmt.c,v 1.3 2017/10/08 10:13:42 bru Exp $ */
/*
* HID multitouch driver for devices conforming to Windows Precision Touchpad
* standard
@@ -41,6 +41,70 @@
#define DPRINTF(x)
#endif
+#define HID_UNIT_CM 0x11
+#define HID_UNIT_INCH 0x13
+
+/*
+ * Calculate the horizontal or vertical resolution, in device units per
+ * millimeter.
+ *
+ * With the length unit specified by the descriptor (centimeter or inch),
+ * the result is:
+ * (logical_maximum - logical_minimum) / ((physical_maximum -
+ * physical_minimum) * 10^unit_exponent)
+ *
+ * The descriptors should encode the unit exponent as a signed half-byte.
+ * However, this function accepts the values from -8 to -1 in both the
+ * 4-bit format and the usual encoding. Other values beyond the 4-bit
+ * range are treated as undefined. Possibly a misinterpretation of
+ * section 6.2.2.7 of the HID specification (v1.11) has been turned into
+ * a standard here, see (from www.usb.org)
+ * HUTRR39: "HID Sensor Usage Tables", sect. 3.9, 3.10, 4.2.1
+ * for an official exegesis and
+ * https://patchwork.kernel.org/patch/3033191
+ * for details and a different view.
+ */
+int
+hidmt_get_resolution(struct hid_item *h)
+{
+ int log_extent, phy_extent, exponent;
+
+ if (h->unit != HID_UNIT_CM && h->unit != HID_UNIT_INCH)
+ return (0);
+
+ log_extent = h->logical_maximum - h->logical_minimum;
+ phy_extent = h->physical_maximum - h->physical_minimum;
+ if (log_extent <= 0 || phy_extent <= 0)
+ return (0);
+
+ exponent = h->unit_exponent;
+ if (exponent < -8 || exponent > 15) /* See above. */
+ return (0);
+ if (exponent > 7)
+ exponent -= 16;
+
+ for (; exponent < 0 && log_extent <= INT_MAX / 10; exponent++)
+ log_extent *= 10;
+ for (; exponent > 0 && phy_extent <= INT_MAX / 10; exponent--)
+ phy_extent *= 10;
+ if (exponent != 0)
+ return (0);
+
+ if (h->unit == HID_UNIT_INCH) { /* Map inches to mm. */
+ if ((phy_extent > INT_MAX / 127)
+ || (log_extent > INT_MAX / 5))
+ return (0);
+ log_extent *= 5;
+ phy_extent *= 127;
+ } else { /* Map cm to mm. */
+ if (phy_extent > INT_MAX / 10)
+ return (0);
+ phy_extent *= 10;
+ }
+
+ return (log_extent / phy_extent);
+}
+
int
hidmt_setup(struct device *self, struct hidmt *mt, void *desc, int dlen)
{
@@ -111,18 +175,18 @@ hidmt_setup(struct device *self, struct hidmt *mt, void *desc, int dlen)
switch (h.usage) {
/* contact level usages */
case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X):
- if (h.physical_minimum < mt->sc_minx)
- mt->sc_minx = h.physical_minimum;
- if (h.physical_maximum > mt->sc_maxx)
- mt->sc_maxx = h.physical_maximum;
-
+ if (h.logical_maximum - h.logical_minimum) {
+ mt->sc_minx = h.logical_minimum;
+ mt->sc_maxx = h.logical_maximum;
+ mt->sc_resx = hidmt_get_resolution(&h);
+ }
break;
case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y):
- if (h.physical_minimum < mt->sc_miny)
- mt->sc_miny = h.physical_minimum;
- if (h.physical_maximum > mt->sc_maxy)
- mt->sc_maxy = h.physical_maximum;
-
+ if (h.logical_maximum - h.logical_minimum) {
+ mt->sc_miny = h.logical_minimum;
+ mt->sc_maxy = h.logical_maximum;
+ mt->sc_resy = hidmt_get_resolution(&h);
+ }
break;
case HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH):
case HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIDENCE):
@@ -162,6 +226,29 @@ hidmt_setup(struct device *self, struct hidmt *mt, void *desc, int dlen)
}
void
+hidmt_configure(struct hidmt *mt)
+{
+ struct wsmousehw *hw;
+
+ if (mt->sc_wsmousedev == NULL)
+ return;
+
+ hw = wsmouse_get_hw(mt->sc_wsmousedev);
+ hw->type = WSMOUSE_TYPE_ELANTECH; /* see hidmt_ioctl */
+ hw->hw_type = (mt->sc_clickpad
+ ? WSMOUSEHW_CLICKPAD : WSMOUSEHW_TOUCHPAD);
+ hw->x_min = mt->sc_minx;
+ hw->x_max = mt->sc_maxx;
+ hw->y_min = mt->sc_miny;
+ hw->y_max = mt->sc_maxy;
+ hw->h_res = mt->sc_resx;
+ hw->v_res = mt->sc_resy;
+ hw->mt_slots = HIDMT_MAX_CONTACTS;
+
+ wsmouse_configure(mt->sc_wsmousedev, NULL, 0);
+}
+
+void
hidmt_attach(struct hidmt *mt, const struct wsmouse_accessops *ops)
{
struct wsmousedev_attach_args a;
@@ -173,6 +260,7 @@ hidmt_attach(struct hidmt *mt, const struct wsmouse_accessops *ops)
a.accessops = ops;
a.accesscookie = mt->sc_device;
mt->sc_wsmousedev = config_found(mt->sc_device, &a, wsmousedevprint);
+ hidmt_configure(mt);
}
int
@@ -199,7 +287,7 @@ hidmt_input(struct hidmt *mt, uint8_t *data, u_int len)
struct hidmt_input *hi;
struct hidmt_contact hc;
int32_t d, firstu = 0;
- int contactcount = 0, seencontacts = 0, tips = 0, i, s;
+ int contactcount = 0, seencontacts = 0, tips = 0, i, s, z;
if (len != mt->sc_rep_input_size) {
DPRINTF(("%s: %s: length %d not %d, ignoring\n",
@@ -240,11 +328,13 @@ hidmt_input(struct hidmt *mt, uint8_t *data, u_int len)
d = hid_get_udata(data, len, &hi->loc);
if (firstu && hi->usage == firstu) {
- if (seencontacts < contactcount &&
- hc.contactid < HIDMT_MAX_CONTACTS) {
+ if (seencontacts < contactcount) {
hc.seen = 1;
- memcpy(&mt->sc_contacts[hc.contactid], &hc,
- sizeof(struct hidmt_contact));
+ i = wsmouse_id_to_slot(
+ mt->sc_wsmousedev, hc.contactid);
+ if (i >= 0)
+ memcpy(&mt->sc_contacts[i], &hc,
+ sizeof(struct hidmt_contact));
seencontacts++;
}
@@ -290,14 +380,17 @@ hidmt_input(struct hidmt *mt, uint8_t *data, u_int len)
break;
}
}
- if (seencontacts < contactcount && hc.contactid < HIDMT_MAX_CONTACTS) {
+ if (seencontacts < contactcount) {
hc.seen = 1;
- memcpy(&mt->sc_contacts[hc.contactid], &hc,
- sizeof(struct hidmt_contact));
+ i = wsmouse_id_to_slot(mt->sc_wsmousedev, hc.contactid);
+ if (i >= 0)
+ memcpy(&mt->sc_contacts[i], &hc,
+ sizeof(struct hidmt_contact));
seencontacts++;
}
s = spltty();
+ wsmouse_buttons(mt->sc_wsmousedev, mt->sc_button);
for (i = 0; i < HIDMT_MAX_CONTACTS; i++) {
if (!mt->sc_contacts[i].seen)
continue;
@@ -321,32 +414,14 @@ hidmt_input(struct hidmt *mt, uint8_t *data, u_int len)
if (mt->sc_contacts[i].tip && !mt->sc_contacts[i].confidence)
continue;
- if (mt->sc_wsmode == WSMOUSE_NATIVE) {
- int width = 0;
- if (mt->sc_contacts[i].tip) {
- width = mt->sc_contacts[i].width;
- if (width < 50)
- width = 50;
- }
-
- WSMOUSE_TOUCH(mt->sc_wsmousedev, mt->sc_button,
- (mt->last_x = mt->sc_contacts[i].x),
- (mt->last_y = mt->sc_contacts[i].y),
- width, tips);
- } else {
- WSMOUSE_INPUT(mt->sc_wsmousedev, mt->sc_button,
- (mt->last_x - mt->sc_contacts[i].x),
- (mt->last_y - mt->sc_contacts[i].y),
- 0, 0);
- mt->last_x = mt->sc_contacts[i].x;
- mt->last_y = mt->sc_contacts[i].y;
- }
+ /* Report width as pressure. */
+ z = (mt->sc_contacts[i].tip
+ ? imax(mt->sc_contacts[i].width, 50) : 0);
- /*
- * XXX: wscons can only handle one finger of data
- */
- break;
+ wsmouse_mtstate(mt->sc_wsmousedev,
+ i, mt->sc_contacts[i].x, mt->sc_contacts[i].y, z);
}
+ wsmouse_input_sync(mt->sc_wsmousedev);
splx(s);
}
@@ -384,8 +459,8 @@ hidmt_ioctl(struct hidmt *mt, u_long cmd, caddr_t data, int flag,
wsmc->miny = mt->sc_miny;
wsmc->maxy = mt->sc_maxy;
wsmc->swapxy = 0;
- wsmc->resx = 0;
- wsmc->resy = 0;
+ wsmc->resx = mt->sc_resx;
+ wsmc->resy = mt->sc_resy;
break;
case WSMOUSEIO_SETMODE:
@@ -399,7 +474,8 @@ hidmt_ioctl(struct hidmt *mt, u_long cmd, caddr_t data, int flag,
DPRINTF(("%s: changing mode to %s\n", mt->sc_device->dv_xname,
(wsmode == WSMOUSE_COMPAT ? "compat" : "native")));
- mt->sc_wsmode = wsmode;
+ wsmouse_set_mode(mt->sc_wsmousedev, wsmode);
+
break;
default:
diff --git a/sys/dev/hid/hidmtvar.h b/sys/dev/hid/hidmtvar.h
index 5cf1329d541..44928af5ef8 100644
--- a/sys/dev/hid/hidmtvar.h
+++ b/sys/dev/hid/hidmtvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hidmtvar.h,v 1.1 2016/01/20 01:26:00 jcs Exp $ */
+/* $OpenBSD: hidmtvar.h,v 1.2 2017/10/08 10:13:42 bru Exp $ */
/*
* Copyright (c) 2016 joshua stein <jcs@openbsd.org>
*
@@ -52,18 +52,16 @@ struct hidmt {
SIMPLEQ_HEAD(, hidmt_input) sc_inputs;
struct device *sc_wsmousedev;
- int sc_wsmode;
int sc_clickpad;
int sc_num_contacts;
#define HIDMT_MAX_CONTACTS 5
int sc_minx, sc_maxx;
int sc_miny, sc_maxy;
+ int sc_resx, sc_resy;
struct hidmt_contact sc_contacts[HIDMT_MAX_CONTACTS];
int sc_button;
-
- int last_x, last_y;
};
int hidmt_set_input_mode(struct hidmt *, int);