Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143809890
D12017.id32015.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D12017.id32015.diff
View Options
Index: share/man/man4/Makefile
===================================================================
--- share/man/man4/Makefile
+++ share/man/man4/Makefile
@@ -562,6 +562,7 @@
wlan_tkip.4 \
wlan_wep.4 \
wlan_xauth.4 \
+ wmt.4 \
${_wpi.4} \
wsp.4 \
xe.4 \
Index: share/man/man4/usb_quirk.4
===================================================================
--- share/man/man4/usb_quirk.4
+++ share/man/man4/usb_quirk.4
@@ -98,6 +98,8 @@
select configuration index 0 by default
.It UQ_ASSUME_CM_OVER_DATA
assume cm over data feature
+.It UQ_WMT_IGNORE
+device should be ignored by wmt driver
.El
.Sh USB Mass Storage quirks:
.Bl -tag -width Ds
Index: share/man/man4/wmt.4
===================================================================
--- /dev/null
+++ share/man/man4/wmt.4
@@ -0,0 +1,84 @@
+.\" Copyright (c) 2014-2017 Vladimir Kondratyev <wulf@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 31, 2017
+.Dt WMT 4
+.Os
+.Sh NAME
+.Nm wmt
+.Nd MS Windows 7/8/10 - compatible USB HID multi-touch device driver
+.Sh SYNOPSIS
+To compile this driver into the kernel, place the following lines into
+your kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device wmt"
+.Cd "device usb"
+.Cd "device evdev"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+wmt_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the MS Windows 7/8/10 - compatible USB HID
+multi-touch devices found in many laptops.
+.Pp
+To get multi-touch device working in
+.Xr X 7 ,
+install
+.Pa ports/x11-drivers/xf86-input-evdev .
+.Sh FILES
+.Nm
+creates a pseudo-device file,
+.Pa /dev/input/eventX
+which presents the multi-touch device as an input event device.
+.Sh SEE ALSO
+.Xr usb 4 ,
+.Xr loader.conf 5 ,
+.Xr xorg.conf 5 Pq Pa ports/x11/xorg ,
+.Xr evdev 4 Pq Pa ports/x11-drivers/xf86-input-evdev .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
+.Sh BUGS
+.Nm
+works only with touchscreens now.
+Neither pens nor touchpads are supported.
+.Pp
+.Nm
+cannot act like
+.Xr sysmouse 4 ,
+as
+.Xr sysmouse 4
+does not support absolute motion events.
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3223,6 +3223,7 @@
dev/usb/input/uhid.c optional uhid
dev/usb/input/ukbd.c optional ukbd
dev/usb/input/ums.c optional ums
+dev/usb/input/wmt.c optional wmt
dev/usb/input/wsp.c optional wsp
#
# USB quirks
Index: sys/dev/usb/input/wmt.c
===================================================================
--- /dev/null
+++ sys/dev/usb/input/wmt.c
@@ -0,0 +1,721 @@
+/*-
+ * Copyright (c) 2014-2017 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * MS Windows 7/8/10 compatible USB HID Multi-touch Device driver.
+ * https://msdn.microsoft.com/en-us/library/windows/hardware/jj151569(v=vs.85).aspx
+ * https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/stddef.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+
+#include "usbdevs.h"
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbhid.h>
+
+#include <dev/usb/quirk/usb_quirk.h>
+
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/input.h>
+
+#define USB_DEBUG_VAR wmt_debug
+#include <dev/usb/usb_debug.h>
+
+#ifdef USB_DEBUG
+static int wmt_debug = 0;
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, wmt, CTLFLAG_RW, 0,
+ "USB MSWindows 7/8/10 compatible Multi-touch Device");
+SYSCTL_INT(_hw_usb_wmt, OID_AUTO, debug, CTLFLAG_RWTUN,
+ &wmt_debug, 1, "Debug level");
+#endif
+
+#define WMT_BSIZE 1024 /* bytes, buffer size */
+
+enum {
+ WMT_INTR_DT,
+ WMT_N_TRANSFER,
+};
+
+enum {
+ WMT_TIP_SWITCH,
+#define WMT_SLOT WMT_TIP_SWITCH
+ WMT_WIDTH,
+#define WMT_MAJOR WMT_WIDTH
+ WMT_HEIGHT,
+#define WMT_MINOR WMT_HEIGHT
+ WMT_ORIENTATION,
+ WMT_X,
+ WMT_Y,
+ WMT_CONTACTID,
+ WMT_PRESSURE,
+ WMT_IN_RANGE,
+ WMT_CONFIDENCE,
+ WMT_TOOL_X,
+ WMT_TOOL_Y,
+ WMT_N_USAGES,
+};
+
+#define WMT_NO_CODE (ABS_MAX + 10)
+#define WMT_NO_USAGE -1
+
+struct wmt_hid_map_item {
+ char name[5];
+ int32_t usage; /* HID usage */
+ uint32_t code; /* Evdev event code */
+ bool required; /* Required for MT Digitizers */
+};
+
+static const struct wmt_hid_map_item wmt_hid_map[WMT_N_USAGES] = {
+
+ [WMT_TIP_SWITCH] = { /* WMT_SLOT */
+ .name = "TIP",
+ .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH),
+ .code = ABS_MT_SLOT,
+ .required = true,
+ },
+ [WMT_WIDTH] = { /* WMT_MAJOR */
+ .name = "WDTH",
+ .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_WIDTH),
+ .code = ABS_MT_TOUCH_MAJOR,
+ .required = false,
+ },
+ [WMT_HEIGHT] = { /* WMT_MINOR */
+ .name = "HGHT",
+ .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_HEIGHT),
+ .code = ABS_MT_TOUCH_MINOR,
+ .required = false,
+ },
+ [WMT_ORIENTATION] = {
+ .name = "ORIE",
+ .usage = WMT_NO_USAGE,
+ .code = ABS_MT_ORIENTATION,
+ .required = false,
+ },
+ [WMT_X] = {
+ .name = "X",
+ .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
+ .code = ABS_MT_POSITION_X,
+ .required = true,
+ },
+ [WMT_Y] = {
+ .name = "Y",
+ .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
+ .code = ABS_MT_POSITION_Y,
+ .required = true,
+ },
+ [WMT_CONTACTID] = {
+ .name = "C_ID",
+ .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID),
+ .code = ABS_MT_TRACKING_ID,
+ .required = true,
+ },
+ [WMT_PRESSURE] = {
+ .name = "PRES",
+ .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_PRESSURE),
+ .code = ABS_MT_PRESSURE,
+ .required = false,
+ },
+ [WMT_IN_RANGE] = {
+ .name = "RANG",
+ .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_IN_RANGE),
+ .code = ABS_MT_DISTANCE,
+ .required = false,
+ },
+ [WMT_CONFIDENCE] = {
+ .name = "CONF",
+ .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIDENCE),
+ .code = WMT_NO_CODE,
+ .required = false,
+ },
+ [WMT_TOOL_X] = { /* Shares HID usage with WMT_X */
+ .name = "TL_X",
+ .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
+ .code = ABS_MT_TOOL_X,
+ .required = false,
+ },
+ [WMT_TOOL_Y] = { /* Shares HID usage with WMT_Y */
+ .name = "TL_Y",
+ .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
+ .code = ABS_MT_TOOL_Y,
+ .required = false,
+ },
+};
+
+struct wmt_absinfo {
+ int32_t min;
+ int32_t max;
+ int32_t res;
+};
+
+struct wmt_softc
+{
+ device_t dev;
+ struct evdev_dev *evdev;
+
+ struct mtx mtx;
+ struct usb_xfer *xfer[WMT_N_TRANSFER];
+ uint32_t isize;
+
+ uint8_t report_id;
+ uint32_t caps;
+ uint32_t nconts_max;
+ struct hid_location nconts_loc;
+ struct hid_location locs[MAX_MT_SLOTS][WMT_N_USAGES];
+ struct wmt_absinfo ai[WMT_N_USAGES];
+ uint32_t slot_data[WMT_N_USAGES];
+
+ uint8_t buf[WMT_BSIZE] __aligned(4);
+};
+
+#define USAGE_SUPPORTED(caps, usage) ((caps) & (1 << (usage)))
+#define WMT_FOREACH_USAGE(caps, usage) \
+ for ((usage) = 0; (usage) < WMT_N_USAGES; ++(usage)) \
+ if (USAGE_SUPPORTED((caps), (usage)))
+
+static bool wmt_hid_parse(struct wmt_softc *, const void *, uint16_t);
+
+static usb_callback_t wmt_intr_callback;
+
+static device_probe_t wmt_probe;
+static device_attach_t wmt_attach;
+static device_detach_t wmt_detach;
+
+static evdev_open_t wmt_ev_open;
+static evdev_close_t wmt_ev_close;
+
+static const struct evdev_methods wmt_evdev_methods = {
+ .ev_open = &wmt_ev_open,
+ .ev_close = &wmt_ev_close,
+};
+
+static const struct usb_config wmt_config[WMT_N_TRANSFER] = {
+
+ [WMT_INTR_DT] = {
+ .type = UE_INTERRUPT,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_IN,
+ .flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
+ .bufsize = WMT_BSIZE,
+ .callback = &wmt_intr_callback,
+ },
+};
+
+static int
+wmt_probe(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ void *d_ptr;
+ uint16_t d_len;
+ int err;
+
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return (ENXIO);
+
+ if (uaa->info.bInterfaceClass != UICLASS_HID)
+ return (ENXIO);
+
+ if (usb_test_quirk(uaa, UQ_WMT_IGNORE))
+ return (ENXIO);
+
+ err = usbd_req_get_hid_desc(uaa->device, NULL,
+ &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
+ if (err)
+ return (ENXIO);
+
+ if (wmt_hid_parse(NULL, d_ptr, d_len))
+ err = BUS_PROBE_DEFAULT;
+ else
+ err = ENXIO;
+
+ free(d_ptr, M_TEMP);
+ return (err);
+}
+
+static int
+wmt_attach(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct wmt_softc *sc = device_get_softc(dev);
+ void *d_ptr;
+ uint16_t d_size;
+ size_t i;
+ int err;
+
+ device_set_usb_desc(dev);
+ sc->dev = dev;
+
+ /* Get HID descriptor */
+ err = usbd_req_get_hid_desc(uaa->device, NULL,
+ &d_ptr, &d_size, M_TEMP, uaa->info.bIfaceIndex);
+ if (err) {
+ DPRINTF("usbd_req_get_hid_desc error=%s\n", usbd_errstr(err));
+ return (ENXIO);
+ }
+
+ mtx_init(&sc->mtx, "wmt lock", NULL, MTX_DEF);
+
+ /* Get HID report length */
+ sc->isize = hid_report_size(d_ptr, d_size, hid_input, NULL);
+ if (sc->isize <= 0 || sc->isize > WMT_BSIZE) {
+ DPRINTF("Input size invalid or too large: %d\n", sc->isize);
+ goto detach;
+ }
+
+ err = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
+ sc->xfer, wmt_config, WMT_N_TRANSFER, sc, &sc->mtx);
+ if (err) {
+ DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err));
+ goto detach;
+ }
+
+ if (!wmt_hid_parse(sc, d_ptr, d_size))
+ goto detach;
+
+ sc->evdev = evdev_alloc();
+ evdev_set_name(sc->evdev, device_get_desc(dev));
+ evdev_set_phys(sc->evdev, device_get_nameunit(dev));
+ evdev_set_id(sc->evdev, BUS_USB, uaa->info.idVendor,
+ uaa->info.idProduct, 0);
+ evdev_set_serial(sc->evdev, usb_get_serial(uaa->device));
+ evdev_set_methods(sc->evdev, sc, &wmt_evdev_methods);
+ evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT);
+ evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT);
+ evdev_support_event(sc->evdev, EV_SYN);
+ evdev_support_event(sc->evdev, EV_ABS);
+ WMT_FOREACH_USAGE(sc->caps, i)
+ if (wmt_hid_map[i].code != WMT_NO_CODE)
+ evdev_support_abs(sc->evdev, wmt_hid_map[i].code, 0,
+ sc->ai[i].min, sc->ai[i].max, 0, 0, sc->ai[i].res);
+
+ err = evdev_register_mtx(sc->evdev, &sc->mtx);
+ if (err)
+ goto detach;
+
+ return (0);
+
+detach:
+ free(d_ptr, M_TEMP);
+ wmt_detach(dev);
+ return (ENXIO);
+}
+
+static int
+wmt_detach(device_t dev)
+{
+ struct wmt_softc *sc = device_get_softc(dev);
+
+ evdev_free(sc->evdev);
+ usbd_transfer_unsetup(sc->xfer, WMT_N_TRANSFER);
+ mtx_destroy(&sc->mtx);
+ return (0);
+}
+
+static void
+wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len)
+{
+ uint32_t cont, nconts, width, height, *slot_data;
+ int32_t slot;
+ size_t usage;
+
+ nconts = hid_get_data_unsigned(buf, len, &sc->nconts_loc);
+
+#ifdef USB_DEBUG
+ DPRINTFN(6, "nconts = %u ", (unsigned)nconts);
+ if (wmt_debug >= 6) {
+ WMT_FOREACH_USAGE(sc->caps, usage)
+ if (wmt_hid_map[usage].usage != WMT_NO_USAGE)
+ printf(" %-4s", wmt_hid_map[usage].name);
+ printf("\n");
+ }
+#endif
+
+ if (nconts > sc->nconts_max) {
+ DPRINTF("Contact count overflow %u\n", (unsigned)nconts);
+ nconts = sc->nconts_max;
+ }
+
+ /* Use protocol Type B for reporting events */
+ slot_data = sc->slot_data;
+ for (cont = 0; cont < nconts; cont++) {
+
+ bzero(slot_data, sizeof(sc->slot_data));
+ WMT_FOREACH_USAGE(sc->caps, usage)
+ if (sc->locs[cont][usage].size > 0)
+ slot_data[usage] = hid_get_data_unsigned(
+ buf, len, &sc->locs[cont][usage]);
+
+ slot = evdev_get_mt_slot_by_tracking_id(sc->evdev,
+ slot_data[WMT_CONTACTID]);
+
+#ifdef USB_DEBUG
+ DPRINTFN(6, "cont%01x: data = ", cont);
+ if (wmt_debug >= 6) {
+ WMT_FOREACH_USAGE(sc->caps, usage)
+ if (wmt_hid_map[usage].usage != WMT_NO_USAGE)
+ printf("%04x ", slot_data[usage]);
+ printf("slot = %d\n", (int)slot);
+ }
+#endif
+
+ if (slot == -1) {
+ DPRINTF("Slot overflow for contact_id %u\n",
+ (unsigned)slot_data[WMT_CONTACTID]);
+ continue;
+ }
+
+ if (slot_data[WMT_TIP_SWITCH] != 0 &&
+ !(USAGE_SUPPORTED(sc->caps, WMT_CONFIDENCE) &&
+ slot_data[WMT_CONFIDENCE] == 0)) {
+ /* This finger is in proximity of the sensor */
+ slot_data[WMT_SLOT] = slot;
+ slot_data[WMT_IN_RANGE] = !slot_data[WMT_IN_RANGE];
+ /* Divided by two to match visual scale of touch */
+ width = slot_data[WMT_WIDTH] >> 1;
+ height = slot_data[WMT_HEIGHT] >> 1;
+ slot_data[WMT_ORIENTATION] = width > height;
+ slot_data[WMT_MAJOR] = MAX(width, height);
+ slot_data[WMT_MINOR] = MIN(width, height);
+
+ WMT_FOREACH_USAGE(sc->caps, usage)
+ if (wmt_hid_map[usage].code != WMT_NO_CODE)
+ evdev_push_abs(sc->evdev,
+ wmt_hid_map[usage].code,
+ slot_data[usage]);
+ } else {
+ evdev_push_abs(sc->evdev, ABS_MT_SLOT, slot);
+ evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1);
+ }
+ }
+ evdev_sync(sc->evdev);
+}
+
+static void
+wmt_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct wmt_softc *sc = usbd_xfer_softc(xfer);
+ struct usb_page_cache *pc;
+ uint8_t *buf = sc->buf;
+ int len;
+
+ usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_TRANSFERRED:
+ pc = usbd_xfer_get_frame(xfer, 0);
+
+ DPRINTFN(6, "sc=%p actlen=%d\n", sc, len);
+
+ if (len >= (int)sc->isize || (len > 0 && sc->report_id != 0)) {
+ /* Limit report length to the maximum */
+ if (len > (int)sc->isize)
+ len = sc->isize;
+
+ usbd_copy_out(pc, 0, buf, len);
+
+ /* Ignore irrelevant reports */
+ if (sc->report_id && *buf != sc->report_id)
+ goto tr_ignore;
+
+ if (len < sc->isize) {
+ /* Make sure we don't process old data */
+ bzero(buf + len, sc->isize - len);
+ }
+
+ /* Strip leading "report ID" byte */
+ if (sc->report_id) {
+ len--;
+ buf++;
+ }
+
+ wmt_process_report(sc, buf, len);
+ } else {
+tr_ignore:
+ DPRINTF("Ignored transfer, %d bytes\n", len);
+ }
+
+ case USB_ST_SETUP:
+tr_setup:
+ usbd_xfer_set_frame_len(xfer, 0, sc->isize);
+ usbd_transfer_submit(xfer);
+ break;
+ default:
+ if (error != USB_ERR_CANCELLED) {
+ /* Try clear stall first */
+ usbd_xfer_set_stall(xfer);
+ goto tr_setup;
+ }
+ break;
+ }
+}
+
+static void
+wmt_ev_close(struct evdev_dev *evdev, void *ev_softc)
+{
+ struct wmt_softc *sc = (struct wmt_softc *)ev_softc;
+
+ mtx_assert(&sc->mtx, MA_OWNED);
+ usbd_transfer_stop(sc->xfer[WMT_INTR_DT]);
+}
+
+static int
+wmt_ev_open(struct evdev_dev *evdev, void *ev_softc)
+{
+ struct wmt_softc *sc = (struct wmt_softc *)ev_softc;
+
+ mtx_assert(&sc->mtx, MA_OWNED);
+ usbd_transfer_start(sc->xfer[WMT_INTR_DT]);
+
+ return (0);
+}
+
+static bool
+wmt_hid_parse(struct wmt_softc *sc, const void *d_ptr, uint16_t d_len)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+ bool touch_coll, finger_coll, cont_count_found, scan_time_found;
+ size_t i, cont;
+ uint32_t caps;
+ int32_t cont_count_max;
+ uint8_t report_id;
+
+#define WMT_HI_ABSOLUTE(hi) \
+ (((hi).flags & (HIO_CONST|HIO_VARIABLE|HIO_RELATIVE)) == HIO_VARIABLE)
+
+ touch_coll = false;
+ cont_count_max = cont = caps = report_id = 0;
+
+ /* Parse features for maximum contact count */
+ hd = hid_start_parse(d_ptr, d_len, 1 << hid_feature);
+ while (hid_get_item(hd, &hi)) {
+ switch (hi.kind) {
+ case hid_collection:
+ if (hi.collevel == 1 && hi.usage ==
+ HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))
+ touch_coll = true;
+ break;
+ case hid_endcollection:
+ if (hi.collevel == 0 && touch_coll)
+ touch_coll = false;
+ break;
+ case hid_feature:
+ if (hi.collevel == 1 && touch_coll &&
+ WMT_HI_ABSOLUTE(hi) && hi.usage ==
+ HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX))
+ cont_count_max = hi.logical_maximum;
+ break;
+ default:
+ break;
+ }
+ }
+ hid_end_parse(hd);
+
+ /* maximum contact count is required usage */
+ if (cont_count_max < 1)
+ return (false);
+
+ touch_coll = finger_coll = cont_count_found = scan_time_found = false;
+
+ /* Parse input for other parameters */
+ hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
+ while (hid_get_item(hd, &hi)) {
+ switch (hi.kind) {
+ case hid_collection:
+ if (hi.collevel == 1 && hi.usage ==
+ HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))
+ touch_coll = true;
+ else if (touch_coll && hi.collevel == 2 &&
+ (report_id == 0 || report_id == hi.report_ID) &&
+ hi.usage == HID_USAGE2(HUP_DIGITIZERS, HUD_FINGER))
+ finger_coll = true;
+ break;
+ case hid_endcollection:
+ if (hi.collevel == 1 && finger_coll) {
+ finger_coll = false;
+ cont++;
+ } else if (hi.collevel == 0 && touch_coll)
+ touch_coll = false;
+ break;
+ case hid_input:
+ /*
+ * Ensure that all usages are located within the same
+ * report and proper collection.
+ */
+ if (WMT_HI_ABSOLUTE(hi) && touch_coll &&
+ (report_id == 0 || report_id == hi.report_ID))
+ report_id = hi.report_ID;
+ else
+ break;
+
+ if (hi.collevel == 1 && hi.usage ==
+ HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTCOUNT)) {
+ cont_count_found = true;
+ if (sc != NULL)
+ sc->nconts_loc = hi.loc;
+ break;
+ }
+ /* Scan time is required but clobbered by evdev */
+ if (hi.collevel == 1 && hi.usage ==
+ HID_USAGE2(HUP_DIGITIZERS, HUD_SCAN_TIME)) {
+ scan_time_found = true;
+ break;
+ }
+
+ if (!finger_coll || hi.collevel != 2)
+ break;
+ if (sc == NULL && cont > 0)
+ break;
+ if (cont >= MAX_MT_SLOTS) {
+ DPRINTF("Finger %zu ignored\n", cont);
+ break;
+ }
+
+ for (i = 0; i < WMT_N_USAGES; i++) {
+ if (hi.usage == wmt_hid_map[i].usage) {
+ if (sc == NULL) {
+ if (USAGE_SUPPORTED(caps, i))
+ continue;
+ caps |= 1 << i;
+ break;
+ }
+ /*
+ * HUG_X usage is an array mapped to
+ * both ABS_MT_POSITION and ABS_MT_TOOL
+ * events. So don`t stop search if we
+ * already have HUG_X mapping done.
+ */
+ if (sc->locs[cont][i].size)
+ continue;
+ sc->locs[cont][i] = hi.loc;
+ /*
+ * Hid parser returns valid logical and
+ * physical sizes for first finger only
+ * at least on ElanTS 0x04f3:0x0012.
+ */
+ if (cont > 0)
+ break;
+ caps |= 1 << i;
+ sc->ai[i] = (struct wmt_absinfo) {
+ .max = hi.logical_maximum,
+ .min = hi.logical_minimum,
+ .res = hid_item_resolution(&hi),
+ };
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ hid_end_parse(hd);
+
+ /* Check for required HID Usages */
+ if (!cont_count_found || !scan_time_found || cont == 0)
+ return (false);
+ for (i = 0; i < WMT_N_USAGES; i++)
+ if (wmt_hid_map[i].required && !USAGE_SUPPORTED(caps, i))
+ return (false);
+
+ /* Stop probing here */
+ if (sc == NULL)
+ return (true);
+
+ /* Cap contact count maximum to MAX_MT_SLOTS */
+ if (cont_count_max > MAX_MT_SLOTS) {
+ DPRINTF("Hardware reported %d contacts while only %d is "
+ "supported\n", (int)cont_count_max, MAX_MT_SLOTS);
+ cont_count_max = MAX_MT_SLOTS;
+ }
+
+ /* Set number of MT protocol type B slots */
+ sc->ai[WMT_SLOT] = (struct wmt_absinfo) {
+ .min = 0,
+ .max = cont_count_max - 1,
+ .res = 0,
+ };
+
+ /* Report touch orientation if both width and height are supported */
+ if (USAGE_SUPPORTED(caps, WMT_WIDTH) &&
+ USAGE_SUPPORTED(caps, WMT_HEIGHT)) {
+ caps |= (1 << WMT_ORIENTATION);
+ sc->ai[WMT_ORIENTATION].max = 1;
+ }
+
+ sc->report_id = report_id;
+ sc->caps = caps;
+ sc->nconts_max = cont;
+
+ /* Announce information about the touch device */
+ device_printf(sc->dev,
+ "%d contacts and [%s%s%s%s%s]. Report range [%d:%d] - [%d:%d]\n",
+ (int)cont_count_max,
+ USAGE_SUPPORTED(sc->caps, WMT_IN_RANGE) ? "R" : "",
+ USAGE_SUPPORTED(sc->caps, WMT_CONFIDENCE) ? "C" : "",
+ USAGE_SUPPORTED(sc->caps, WMT_WIDTH) ? "W" : "",
+ USAGE_SUPPORTED(sc->caps, WMT_HEIGHT) ? "H" : "",
+ USAGE_SUPPORTED(sc->caps, WMT_PRESSURE) ? "P" : "",
+ (int)sc->ai[WMT_X].min, (int)sc->ai[WMT_Y].min,
+ (int)sc->ai[WMT_X].max, (int)sc->ai[WMT_Y].max);
+ return (true);
+}
+
+static devclass_t wmt_devclass;
+
+static device_method_t wmt_methods[] = {
+ DEVMETHOD(device_probe, wmt_probe),
+ DEVMETHOD(device_attach, wmt_attach),
+ DEVMETHOD(device_detach, wmt_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t wmt_driver = {
+ .name = "wmt",
+ .methods = wmt_methods,
+ .size = sizeof(struct wmt_softc),
+};
+
+DRIVER_MODULE(wmt, uhub, wmt_driver, wmt_devclass, NULL, 0);
+MODULE_DEPEND(wmt, usb, 1, 1, 1);
+MODULE_DEPEND(wmt, evdev, 1, 1, 1);
+MODULE_VERSION(wmt, 1);
Index: sys/dev/usb/quirk/usb_quirk.h
===================================================================
--- sys/dev/usb/quirk/usb_quirk.h
+++ sys/dev/usb/quirk/usb_quirk.h
@@ -110,6 +110,7 @@
UQ_SINGLE_CMD_MIDI, /* at most one command per USB packet */
UQ_MSC_DYMO_EJECT, /* ejects Dymo MSC device */
UQ_AU_SET_SPDIF_CM6206, /* enable S/PDIF audio output */
+ UQ_WMT_IGNORE, /* device should be ignored by wmt driver */
USB_QUIRK_MAX
};
Index: sys/dev/usb/quirk/usb_quirk.c
===================================================================
--- sys/dev/usb/quirk/usb_quirk.c
+++ sys/dev/usb/quirk/usb_quirk.c
@@ -606,6 +606,7 @@
[UQ_SINGLE_CMD_MIDI] = "UQ_SINGLE_CMD_MIDI",
[UQ_MSC_DYMO_EJECT] = "UQ_MSC_DYMO_EJECT",
[UQ_AU_SET_SPDIF_CM6206] = "UQ_AU_SET_SPDIF_CM6206",
+ [UQ_WMT_IGNORE] = "UQ_WMT_IGNORE",
};
/*------------------------------------------------------------------------*
Index: sys/dev/usb/usb_hid.c
===================================================================
--- sys/dev/usb/usb_hid.c
+++ sys/dev/usb/usb_hid.c
@@ -849,6 +849,76 @@
return (USB_ERR_NORMAL_COMPLETION);
}
+/*------------------------------------------------------------------------*
+ * calculate HID item resolution. unit/mm for distances, unit/rad for angles
+ *------------------------------------------------------------------------*/
+int32_t
+hid_item_resolution(struct hid_item *hi)
+{
+ /*
+ * hid unit scaling table according to HID Usage Table Review
+ * Request 39 Tbl 17 http://www.usb.org/developers/hidpage/HUTRR39b.pdf
+ */
+ static const int64_t scale[][2] = {
+ { 1, 1 }, /* 0x00 */
+ { 1, 10 }, /* 0x01 */
+ { 1, 100 }, /* 0x02 */
+ { 1, 1000 }, /* 0x03 */
+ { 1, 10000 }, /* 0x04 */
+ { 1, 100000 }, /* 0x05 */
+ { 1, 1000000 }, /* 0x06 */
+ { 1, 10000000 }, /* 0x07 */
+ { 100000000, 1 }, /* 0x08 */
+ { 10000000, 1 }, /* 0x09 */
+ { 1000000, 1 }, /* 0x0A */
+ { 100000, 1 }, /* 0x0B */
+ { 10000, 1 }, /* 0x0C */
+ { 1000, 1 }, /* 0x0D */
+ { 100, 1 }, /* 0x0E */
+ { 10, 1 }, /* 0x0F */
+ };
+ int64_t logical_size, physical_size, resolution, multiplier, divisor;
+
+ switch (hi->unit) {
+ case HUM_CENTIMETER:
+ multiplier = 1;
+ divisor = 10;
+ break;
+ case HUM_INCH:
+ multiplier = 10;
+ divisor = 254;
+ break;
+ case HUM_RADIAN:
+ multiplier = 1;
+ divisor = 1;
+ break;
+ case HUM_DEGREE:
+ multiplier = 573;
+ divisor = 10;
+ break;
+ default:
+ return (0);
+ }
+
+ if ((hi->logical_maximum <= hi->logical_minimum) ||
+ (hi->physical_maximum <= hi->physical_minimum) ||
+ (hi->unit_exponent < 0) || (hi->unit_exponent >= nitems(scale)))
+ return (0);
+
+ logical_size = (int64_t)hi->logical_maximum -
+ (int64_t)hi->logical_minimum;
+ physical_size = (int64_t)hi->physical_maximum -
+ (int64_t)hi->physical_minimum;
+ /* Round to ceiling */
+ resolution = logical_size * multiplier * scale[hi->unit_exponent][0] /
+ (physical_size * divisor * scale[hi->unit_exponent][1]);
+
+ if (resolution > INT32_MAX)
+ return (0);
+
+ return (resolution);
+}
+
/*------------------------------------------------------------------------*
* hid_is_mouse
*
Index: sys/dev/usb/usbhid.h
===================================================================
--- sys/dev/usb/usbhid.h
+++ sys/dev/usb/usbhid.h
@@ -134,6 +134,12 @@
/* Usages Digitizers */
#define HUD_UNDEFINED 0x0000
+#define HUD_DIGITIZER 0x0001
+#define HUD_PEN 0x0002
+#define HUD_TOUCHSCREEN 0x0004
+#define HUD_TOUCHPAD 0x0005
+#define HUD_CONFIG 0x000e
+#define HUD_FINGER 0x0022
#define HUD_TIP_PRESSURE 0x0030
#define HUD_BARREL_PRESSURE 0x0031
#define HUD_IN_RANGE 0x0032
@@ -157,6 +163,16 @@
#define HUD_BARREL_SWITCH 0x0044
#define HUD_ERASER 0x0045
#define HUD_TABLET_PICK 0x0046
+#define HUD_CONFIDENCE 0x0047
+#define HUD_WIDTH 0x0048
+#define HUD_HEIGHT 0x0049
+#define HUD_CONTACTID 0x0051
+#define HUD_INPUT_MODE 0x0052
+#define HUD_DEVICE_INDEX 0x0053
+#define HUD_CONTACTCOUNT 0x0054
+#define HUD_CONTACT_MAX 0x0055
+#define HUD_SCAN_TIME 0x0056
+#define HUD_BUTTON_TYPE 0x0059
/* Usages, Consumer */
#define HUC_AC_PAN 0x0238
@@ -178,6 +194,12 @@
#define HIO_VOLATILE 0x080
#define HIO_BUFBYTES 0x100
+/* Units of Measure */
+#define HUM_CENTIMETER 0x11
+#define HUM_RADIAN 0x12
+#define HUM_INCH 0x13
+#define HUM_DEGREE 0x14
+
#ifdef _KERNEL
struct usb_config_descriptor;
@@ -244,6 +266,7 @@
usb_error_t usbd_req_get_hid_desc(struct usb_device *udev, struct mtx *mtx,
void **descp, uint16_t *sizep, struct malloc_type *mem,
uint8_t iface_index);
+int32_t hid_item_resolution(struct hid_item *hi);
int hid_is_mouse(const void *d_ptr, uint16_t d_len);
int hid_is_keyboard(const void *d_ptr, uint16_t d_len);
#endif /* _KERNEL */
Index: sys/modules/usb/Makefile
===================================================================
--- sys/modules/usb/Makefile
+++ sys/modules/usb/Makefile
@@ -47,7 +47,7 @@
SUBDIR += ${_dwc_otg} ehci ${_musb} ohci uhci xhci ${_uss820dci} ${_at91dci} \
${_atmegadci} ${_avr32dci} ${_rsu} ${_rsufw} ${_saf1761otg}
SUBDIR += ${_rum} ${_run} ${_runfw} ${_uath} upgt usie ural ${_zyd} ${_urtw}
-SUBDIR += atp cfumass uhid ukbd ums udbp ufm uep wsp ugold uled
+SUBDIR += atp cfumass uhid ukbd ums udbp ufm uep wmt wsp ugold uled
SUBDIR += ucom u3g uark ubsa ubser uchcom ucycom ufoma uftdi ugensa uipaq ulpt \
umct umcs umodem umoscom uplcom uslcom uvisor uvscom
SUBDIR += udl
Index: sys/modules/usb/wmt/Makefile
===================================================================
--- /dev/null
+++ sys/modules/usb/wmt/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+S= ${.CURDIR}/../../..
+
+.PATH: $S/dev/usb/input
+
+KMOD= wmt
+SRCS= opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h usbdevs.h wmt.c
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 1, 2:47 PM (17 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28393558
Default Alt Text
D12017.id32015.diff (28 KB)
Attached To
Mode
D12017: wmt: Driver for generic MS Windows 7/8/10 - compatible USB HID multi-touch devices
Attached
Detach File
Event Timeline
Log In to Comment