Date: Thu, 7 Jan 2021 23:20:51 GMT From: Vladimir Kondratyev <wulf@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: cb022db825e7 - main - hid: Port multitouch hmt(4) driver to hidbus and attach to build Message-ID: <202101072320.107NKpeN063149@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by wulf: URL: https://cgit.FreeBSD.org/src/commit/?id=cb022db825e72ec4d2a8a2b9ff9fd80368e6e309 commit cb022db825e72ec4d2a8a2b9ff9fd80368e6e309 Author: Vladimir Kondratyev <wulf@FreeBSD.org> AuthorDate: 2020-10-10 23:42:25 +0000 Commit: Vladimir Kondratyev <wulf@FreeBSD.org> CommitDate: 2021-01-07 23:18:43 +0000 hid: Port multitouch hmt(4) driver to hidbus and attach to build Reviewed by: hselasky Differential revision: https://reviews.freebsd.org/D27990 --- share/man/man4/Makefile | 1 + share/man/man4/hmt.4 | 25 +- sys/conf/files | 1 + sys/dev/hid/hmt.c | 849 ++++++++++++++++++------------------------- sys/modules/hid/Makefile | 3 +- sys/modules/hid/hmt/Makefile | 9 + 6 files changed, 383 insertions(+), 505 deletions(-) diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 477ea009a153..c92c8f50545f 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -183,6 +183,7 @@ MAN= aac.4 \ hidbus.4 \ hidquirk.4 \ hifn.4 \ + hmt.4 \ hpet.4 \ ${_hpt27xx.4} \ ${_hptiop.4} \ diff --git a/share/man/man4/hmt.4 b/share/man/man4/hmt.4 index e09fc5286fe2..d939c655d24d 100644 --- a/share/man/man4/hmt.4 +++ b/share/man/man4/hmt.4 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2014-2017 Vladimir Kondratyev <wulf@FreeBSD.org> +.\" Copyright (c) 2014-2020 Vladimir Kondratyev <wulf@FreeBSD.org> .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -24,32 +24,34 @@ .\" .\" $FreeBSD$ .\" -.Dd August 19, 2017 -.Dt WMT 4 +.Dd August 11, 2020 +.Dt HMT 4 .Os .Sh NAME -.Nm wmt -.Nd MS Windows 7/8/10 - compatible USB HID multi-touch device driver +.Nm hmt +.Nd MS Windows 7/8/10 - compatible 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 hmt" +.Cd "device hidbus" .Cd "device hid" +.Cd "device hconf" .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" +hmt_load="YES" .Ed .Sh DESCRIPTION The .Nm -driver provides support for the MS Windows 7/8/10 - compatible USB HID +driver provides support for the MS Windows 7/8/10 - compatible HID multi-touch devices found in many laptops. .Pp To get multi-touch device working in @@ -62,7 +64,7 @@ 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 hid 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 . @@ -75,7 +77,4 @@ driver was written by .Sh BUGS .Nm cannot act like -.Xr sysmouse 4 , -as .Xr sysmouse 4 -does not support absolute motion events. diff --git a/sys/conf/files b/sys/conf/files index bd6b510f204c..13dd93d9d2cd 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1820,6 +1820,7 @@ dev/hid/hid.c optional hid dev/hid/hid_if.m optional hid dev/hid/hidbus.c optional hidbus dev/hid/hidquirk.c optional hid +dev/hid/hmt.c optional hmt hconf dev/hifn/hifn7751.c optional hifn dev/hptiop/hptiop.c optional hptiop scbus dev/hwpmc/hwpmc_logging.c optional hwpmc diff --git a/sys/dev/hid/hmt.c b/sys/dev/hid/hmt.c index 79ed5a2b8f82..6cfe43157e64 100644 --- a/sys/dev/hid/hmt.c +++ b/sys/dev/hid/hmt.c @@ -1,6 +1,7 @@ /*- - * Copyright (c) 2014-2017 Vladimir Kondratyev <wulf@FreeBSD.org> - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2014-2020 Vladimir Kondratyev <wulf@FreeBSD.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,168 +29,149 @@ __FBSDID("$FreeBSD$"); /* - * MS Windows 7/8/10 compatible USB HID Multi-touch Device driver. + * MS Windows 7/8/10 compatible HID Multi-touch Device driver. * https://msdn.microsoft.com/en-us/library/windows/hardware/jj151569(v=vs.85).aspx + * http://download.microsoft.com/download/7/d/d/7dd44bb7-2a7a-4505-ac1c-7227d3d96d5b/hid-over-i2c-protocol-spec-v1-0.docx * 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 <dev/hid/hid.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> - -static SYSCTL_NODE(_hw_usb, OID_AUTO, wmt, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, - "USB MSWindows 7/8/10 compatible Multi-touch Device"); -#ifdef USB_DEBUG -static int wmt_debug = 0; -SYSCTL_INT(_hw_usb_wmt, OID_AUTO, debug, CTLFLAG_RWTUN, - &wmt_debug, 1, "Debug level"); -#endif -static bool wmt_timestamps = 0; -SYSCTL_BOOL(_hw_usb_wmt, OID_AUTO, timestamps, CTLFLAG_RDTUN, - &wmt_timestamps, 1, "Enable hardware timestamp reporting"); +#define HID_DEBUG_VAR hmt_debug +#include <dev/hid/hid.h> +#include <dev/hid/hidbus.h> +#include <dev/hid/hidquirk.h> -#define WMT_BSIZE 1024 /* bytes, buffer size */ -#define WMT_BTN_MAX 8 /* Number of buttons supported */ +#include <dev/hid/hconf.h> -enum { - WMT_INTR_DT, - WMT_N_TRANSFER, -}; +static SYSCTL_NODE(_hw_hid, OID_AUTO, hmt, CTLFLAG_RW, 0, + "MSWindows 7/8/10 compatible HID Multi-touch Device"); +#ifdef HID_DEBUG +static int hmt_debug = 0; +SYSCTL_INT(_hw_hid_hmt, OID_AUTO, debug, CTLFLAG_RWTUN, + &hmt_debug, 1, "Debug level"); +#endif +static bool hmt_timestamps = 0; +SYSCTL_BOOL(_hw_hid_hmt, OID_AUTO, timestamps, CTLFLAG_RDTUN, + &hmt_timestamps, 1, "Enable hardware timestamp reporting"); -enum wmt_type { - WMT_TYPE_UNKNOWN = 0, /* HID report descriptor is not probed */ - WMT_TYPE_UNSUPPORTED, /* Repdescr does not belong to MT device */ - WMT_TYPE_TOUCHPAD, - WMT_TYPE_TOUCHSCREEN, -}; +#define HMT_BTN_MAX 8 /* Number of buttons supported */ -enum wmt_input_mode { - WMT_INPUT_MODE_MOUSE = 0x0, - WMT_INPUT_MODE_MT_TOUCHSCREEN = 0x2, - WMT_INPUT_MODE_MT_TOUCHPAD = 0x3, +enum hmt_type { + HMT_TYPE_UNKNOWN = 0, /* HID report descriptor is not probed */ + HMT_TYPE_UNSUPPORTED, /* Repdescr does not belong to MT device */ + HMT_TYPE_TOUCHPAD, + HMT_TYPE_TOUCHSCREEN, }; 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, + HMT_TIP_SWITCH, +#define HMT_SLOT HMT_TIP_SWITCH + HMT_WIDTH, +#define HMT_MAJOR HMT_WIDTH + HMT_HEIGHT, +#define HMT_MINOR HMT_HEIGHT + HMT_ORIENTATION, + HMT_X, + HMT_Y, + HMT_CONTACTID, + HMT_PRESSURE, + HMT_IN_RANGE, + HMT_CONFIDENCE, + HMT_TOOL_X, + HMT_TOOL_Y, + HMT_N_USAGES, }; -#define WMT_NO_CODE (ABS_MAX + 10) -#define WMT_NO_USAGE -1 +#define HMT_NO_CODE (ABS_MAX + 10) +#define HMT_NO_USAGE -1 -struct wmt_hid_map_item { +struct hmt_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 */ +static const struct hmt_hid_map_item hmt_hid_map[HMT_N_USAGES] = { + [HMT_TIP_SWITCH] = { /* HMT_SLOT */ .name = "TIP", .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH), .code = ABS_MT_SLOT, .required = true, }, - [WMT_WIDTH] = { /* WMT_MAJOR */ + [HMT_WIDTH] = { /* HMT_MAJOR */ .name = "WDTH", .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_WIDTH), .code = ABS_MT_TOUCH_MAJOR, .required = false, }, - [WMT_HEIGHT] = { /* WMT_MINOR */ + [HMT_HEIGHT] = { /* HMT_MINOR */ .name = "HGHT", .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_HEIGHT), .code = ABS_MT_TOUCH_MINOR, .required = false, }, - [WMT_ORIENTATION] = { + [HMT_ORIENTATION] = { .name = "ORIE", - .usage = WMT_NO_USAGE, + .usage = HMT_NO_USAGE, .code = ABS_MT_ORIENTATION, .required = false, }, - [WMT_X] = { + [HMT_X] = { .name = "X", .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), .code = ABS_MT_POSITION_X, .required = true, }, - [WMT_Y] = { + [HMT_Y] = { .name = "Y", .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), .code = ABS_MT_POSITION_Y, .required = true, }, - [WMT_CONTACTID] = { + [HMT_CONTACTID] = { .name = "C_ID", .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID), .code = ABS_MT_TRACKING_ID, .required = true, }, - [WMT_PRESSURE] = { + [HMT_PRESSURE] = { .name = "PRES", .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_PRESSURE), .code = ABS_MT_PRESSURE, .required = false, }, - [WMT_IN_RANGE] = { + [HMT_IN_RANGE] = { .name = "RANG", .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_IN_RANGE), .code = ABS_MT_DISTANCE, .required = false, }, - [WMT_CONFIDENCE] = { + [HMT_CONFIDENCE] = { .name = "CONF", .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIDENCE), - .code = WMT_NO_CODE, + .code = HMT_NO_CODE, .required = false, }, - [WMT_TOOL_X] = { /* Shares HID usage with WMT_X */ + [HMT_TOOL_X] = { /* Shares HID usage with HMT_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 */ + [HMT_TOOL_Y] = { /* Shares HID usage with HMT_Y */ .name = "TL_Y", .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), .code = ABS_MT_TOOL_Y, @@ -197,21 +179,14 @@ static const struct wmt_hid_map_item wmt_hid_map[WMT_N_USAGES] = { }, }; -struct wmt_absinfo { - int32_t min; - int32_t max; - int32_t res; -}; - -struct wmt_softc { +struct hmt_softc { device_t dev; - enum wmt_type type; + enum hmt_type type; - struct mtx mtx; - struct wmt_absinfo ai[WMT_N_USAGES]; - struct hid_location locs[MAX_MT_SLOTS][WMT_N_USAGES]; + struct hid_absinfo ai[HMT_N_USAGES]; + struct hid_location locs[MAX_MT_SLOTS][HMT_N_USAGES]; struct hid_location cont_count_loc; - struct hid_location btn_loc[WMT_BTN_MAX]; + struct hid_location btn_loc[HMT_BTN_MAX]; struct hid_location int_btn_loc; struct hid_location scan_time_loc; int32_t scan_time_max; @@ -220,21 +195,19 @@ struct wmt_softc { bool touch; bool prev_touch; - struct usb_xfer *xfer[WMT_N_TRANSFER]; struct evdev_dev *evdev; - uint32_t slot_data[WMT_N_USAGES]; - uint8_t caps[howmany(WMT_N_USAGES, 8)]; - uint8_t buttons[howmany(WMT_BTN_MAX, 8)]; - uint32_t isize; + uint32_t slot_data[HMT_N_USAGES]; + uint8_t caps[howmany(HMT_N_USAGES, 8)]; + uint8_t buttons[howmany(HMT_BTN_MAX, 8)]; uint32_t nconts_per_report; uint32_t nconts_todo; - uint32_t report_len; uint8_t report_id; uint32_t max_button; bool has_int_button; bool is_clickpad; bool do_timestamps; + bool iichid_sampling; struct hid_location cont_max_loc; uint32_t cont_max_rlen; @@ -244,199 +217,186 @@ struct wmt_softc { uint8_t btn_type_rid; uint32_t thqa_cert_rlen; uint8_t thqa_cert_rid; - struct hid_location input_mode_loc; - uint32_t input_mode_rlen; - uint8_t input_mode_rid; - - uint8_t buf[WMT_BSIZE] __aligned(4); }; -#define WMT_FOREACH_USAGE(caps, usage) \ - for ((usage) = 0; (usage) < WMT_N_USAGES; ++(usage)) \ +#define HMT_FOREACH_USAGE(caps, usage) \ + for ((usage) = 0; (usage) < HMT_N_USAGES; ++(usage)) \ if (isset((caps), (usage))) -static enum wmt_type wmt_hid_parse(struct wmt_softc *, const void *, uint16_t); -static int wmt_set_input_mode(struct wmt_softc *, enum wmt_input_mode); +static enum hmt_type hmt_hid_parse(struct hmt_softc *, const void *, + hid_size_t, uint32_t, uint8_t); +static int hmt_set_input_mode(struct hmt_softc *, enum hconf_input_mode); -static usb_callback_t wmt_intr_callback; +static hid_intr_t hmt_intr; -static device_probe_t wmt_probe; -static device_attach_t wmt_attach; -static device_detach_t wmt_detach; +static device_probe_t hmt_probe; +static device_attach_t hmt_attach; +static device_detach_t hmt_detach; -#if __FreeBSD_version >= 1200077 -static evdev_open_t wmt_ev_open; -static evdev_close_t wmt_ev_close; -#else -static evdev_open_t wmt_ev_open_11; -static evdev_close_t wmt_ev_close_11; -#endif +static evdev_open_t hmt_ev_open; +static evdev_close_t hmt_ev_close; -static const struct evdev_methods wmt_evdev_methods = { -#if __FreeBSD_version >= 1200077 - .ev_open = &wmt_ev_open, - .ev_close = &wmt_ev_close, -#else - .ev_open = &wmt_ev_open_11, - .ev_close = &wmt_ev_close_11, -#endif +static const struct evdev_methods hmt_evdev_methods = { + .ev_open = &hmt_ev_open, + .ev_close = &hmt_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 const struct hid_device_id hmt_devs[] = { + { HID_TLC(HUP_DIGITIZERS, HUD_TOUCHSCREEN) }, + { HID_TLC(HUP_DIGITIZERS, HUD_TOUCHPAD) }, }; static int -wmt_probe(device_t dev) +hmt_ev_close(struct evdev_dev *evdev) { - struct usb_attach_arg *uaa = device_get_ivars(dev); - struct wmt_softc *sc = device_get_softc(dev); + return (hidbus_intr_stop(evdev_get_softc(evdev))); +} + +static int +hmt_ev_open(struct evdev_dev *evdev) +{ + return (hidbus_intr_start(evdev_get_softc(evdev))); +} + +static int +hmt_probe(device_t dev) +{ + struct hmt_softc *sc = device_get_softc(dev); void *d_ptr; - uint16_t d_len; + hid_size_t d_len; int err; - if (uaa->usb_mode != USB_MODE_HOST) - return (ENXIO); - - if (uaa->info.bInterfaceClass != UICLASS_HID) - return (ENXIO); + err = HIDBUS_LOOKUP_DRIVER_INFO(dev, hmt_devs); + if (err != 0) + return (err); - if (usb_test_quirk(uaa, UQ_WMT_IGNORE)) + err = hid_get_report_descr(dev, &d_ptr, &d_len); + if (err != 0) { + device_printf(dev, "could not retrieve report descriptor from " + "device: %d\n", err); return (ENXIO); + } - err = usbd_req_get_hid_desc(uaa->device, NULL, - &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex); - if (err) + /* Check if report descriptor belongs to a HID multitouch device */ + if (sc->type == HMT_TYPE_UNKNOWN) + sc->type = hmt_hid_parse(sc, d_ptr, d_len, + hidbus_get_usage(dev), hidbus_get_index(dev)); + if (sc->type == HMT_TYPE_UNSUPPORTED) return (ENXIO); - /* Check if report descriptor belongs to a HID multitouch device */ - if (sc->type == WMT_TYPE_UNKNOWN) - sc->type = wmt_hid_parse(sc, d_ptr, d_len); - if (sc->type != WMT_TYPE_UNSUPPORTED) - err = BUS_PROBE_DEFAULT; - else - err = ENXIO; - - /* Check HID report length */ - if (sc->type != WMT_TYPE_UNSUPPORTED && - (sc->isize <= 0 || sc->isize > WMT_BSIZE)) { - DPRINTF("Input size invalid or too large: %d\n", sc->isize); - err = ENXIO; - } + hidbus_set_desc(dev, + sc->type == HMT_TYPE_TOUCHPAD ? "TouchPad" : "TouchScreen"); - free(d_ptr, M_TEMP); - return (err); + return (BUS_PROBE_DEFAULT); } static int -wmt_attach(device_t dev) +hmt_attach(device_t dev) { - struct usb_attach_arg *uaa = device_get_ivars(dev); - struct wmt_softc *sc = device_get_softc(dev); + struct hmt_softc *sc = device_get_softc(dev); + const struct hid_device_info *hw = hid_get_device_info(dev); + void *d_ptr; + uint8_t *fbuf = NULL; + hid_size_t d_len, fsize; uint32_t cont_count_max; int nbuttons, btn; size_t i; int err; - device_set_usb_desc(dev); + err = hid_get_report_descr(dev, &d_ptr, &d_len); + if (err != 0) { + device_printf(dev, "could not retrieve report descriptor from " + "device: %d\n", err); + return (ENXIO); + } + sc->dev = dev; + fsize = hid_report_size_max(d_ptr, d_len, hid_feature, NULL); + if (fsize != 0) + fbuf = malloc(fsize, M_TEMP, M_WAITOK | M_ZERO); + /* Fetch and parse "Contact count maximum" feature report */ - if (sc->cont_max_rlen > 0 && sc->cont_max_rlen <= WMT_BSIZE) { - err = usbd_req_get_report(uaa->device, NULL, sc->buf, - sc->cont_max_rlen, uaa->info.bIfaceIndex, - UHID_FEATURE_REPORT, sc->cont_max_rid); - if (err == USB_ERR_NORMAL_COMPLETION) { - cont_count_max = hid_get_udata(sc->buf + 1, + if (sc->cont_max_rlen > 1) { + err = hid_get_report(dev, fbuf, sc->cont_max_rlen, NULL, + HID_FEATURE_REPORT, sc->cont_max_rid); + if (err == 0) { + cont_count_max = hid_get_udata(fbuf + 1, sc->cont_max_rlen - 1, &sc->cont_max_loc); /* * Feature report is a primary source of * 'Contact Count Maximum' */ if (cont_count_max > 0) - sc->ai[WMT_SLOT].max = cont_count_max - 1; + sc->ai[HMT_SLOT].max = cont_count_max - 1; } else - DPRINTF("usbd_req_get_report error=(%s)\n", - usbd_errstr(err)); + DPRINTF("hid_get_report error=%d\n", err); } else - DPRINTF("Feature report %hhu size invalid or too large: %u\n", + DPRINTF("Feature report %hhu size invalid: %u\n", sc->cont_max_rid, sc->cont_max_rlen); /* Fetch and parse "Button type" feature report */ - if (sc->btn_type_rlen > 1 && sc->btn_type_rlen <= WMT_BSIZE && - sc->btn_type_rid != sc->cont_max_rid) { - bzero(sc->buf, sc->btn_type_rlen); - err = usbd_req_get_report(uaa->device, NULL, sc->buf, - sc->btn_type_rlen, uaa->info.bIfaceIndex, - UHID_FEATURE_REPORT, sc->btn_type_rid); + if (sc->btn_type_rlen > 1 && sc->btn_type_rid != sc->cont_max_rid) { + bzero(fbuf, fsize); + err = hid_get_report(dev, fbuf, sc->btn_type_rlen, NULL, + HID_FEATURE_REPORT, sc->btn_type_rid); } if (sc->btn_type_rlen > 1) { if (err == 0) - sc->is_clickpad = hid_get_udata(sc->buf + 1, + sc->is_clickpad = hid_get_udata(fbuf + 1, sc->btn_type_rlen - 1, &sc->btn_type_loc) == 0; else - DPRINTF("usbd_req_get_report error=%d\n", err); + DPRINTF("hid_get_report error=%d\n", err); } /* Fetch THQA certificate to enable some devices like WaveShare */ - if (sc->thqa_cert_rlen > 0 && sc->thqa_cert_rlen <= WMT_BSIZE && - sc->thqa_cert_rid != sc->cont_max_rid) - (void)usbd_req_get_report(uaa->device, NULL, sc->buf, - sc->thqa_cert_rlen, uaa->info.bIfaceIndex, - UHID_FEATURE_REPORT, sc->thqa_cert_rid); + if (sc->thqa_cert_rlen > 1 && sc->thqa_cert_rid != sc->cont_max_rid) + (void)hid_get_report(dev, fbuf, sc->thqa_cert_rlen, NULL, + HID_FEATURE_REPORT, sc->thqa_cert_rid); + + free(fbuf, M_TEMP); /* Switch touchpad in to absolute multitouch mode */ - if (sc->type == WMT_TYPE_TOUCHPAD) { - err = wmt_set_input_mode(sc, WMT_INPUT_MODE_MT_TOUCHPAD); + if (sc->type == HMT_TYPE_TOUCHPAD) { + err = hmt_set_input_mode(sc, HCONF_INPUT_MODE_MT_TOUCHPAD); if (err != 0) DPRINTF("Failed to set input mode: %d\n", err); } /* Cap contact count maximum to MAX_MT_SLOTS */ - if (sc->ai[WMT_SLOT].max >= MAX_MT_SLOTS) { + if (sc->ai[HMT_SLOT].max >= MAX_MT_SLOTS) { DPRINTF("Hardware reported %d contacts while only %d is " - "supported\n", (int)sc->ai[WMT_SLOT].max+1, MAX_MT_SLOTS); - sc->ai[WMT_SLOT].max = MAX_MT_SLOTS - 1; + "supported\n", (int)sc->ai[HMT_SLOT].max+1, MAX_MT_SLOTS); + sc->ai[HMT_SLOT].max = MAX_MT_SLOTS - 1; } - if (/*usb_test_quirk(hw, UQ_MT_TIMESTAMP) ||*/ wmt_timestamps) + if (hid_test_quirk(hw, HQ_MT_TIMESTAMP) || hmt_timestamps) sc->do_timestamps = true; + if (hid_test_quirk(hw, HQ_IICHID_SAMPLING)) + sc->iichid_sampling = true; - mtx_init(&sc->mtx, "wmt lock", NULL, MTX_DEF); - - err = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, - sc->xfer, wmt_config, WMT_N_TRANSFER, sc, &sc->mtx); - if (err != USB_ERR_NORMAL_COMPLETION) { - DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err)); - goto detach; - } + hidbus_set_intr(dev, hmt_intr, sc); 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_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct, + hw->idVersion); + evdev_set_serial(sc->evdev, hw->serial); + evdev_set_methods(sc->evdev, dev, &hmt_evdev_methods); evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT); + evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */ switch (sc->type) { - case WMT_TYPE_TOUCHSCREEN: + case HMT_TYPE_TOUCHSCREEN: evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT); break; - case WMT_TYPE_TOUCHPAD: + case HMT_TYPE_TOUCHPAD: evdev_support_prop(sc->evdev, INPUT_PROP_POINTER); if (sc->is_clickpad) evdev_support_prop(sc->evdev, INPUT_PROP_BUTTONPAD); break; default: - KASSERT(0, ("wmt_attach: unsupported touch device type")); + KASSERT(0, ("hmt_attach: unsupported touch device type")); } evdev_support_event(sc->evdev, EV_SYN); evdev_support_event(sc->evdev, EV_ABS); @@ -444,6 +404,8 @@ wmt_attach(device_t dev) evdev_support_event(sc->evdev, EV_MSC); evdev_support_msc(sc->evdev, MSC_TIMESTAMP); } + if (sc->iichid_sampling) + evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_AUTOREL); nbuttons = 0; if (sc->max_button != 0 || sc->has_int_button) { evdev_support_event(sc->evdev, EV_KEY); @@ -456,53 +418,51 @@ wmt_attach(device_t dev) } } } - 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, + HMT_FOREACH_USAGE(sc->caps, i) { + if (hmt_hid_map[i].code != HMT_NO_CODE) + evdev_support_abs(sc->evdev, hmt_hid_map[i].code, 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; + err = evdev_register(sc->evdev); + if (err) { + hmt_detach(dev); + return (ENXIO); + } /* Announce information about the touch device */ device_printf(sc->dev, "Multitouch %s with %d external button%s%s\n", - sc->type == WMT_TYPE_TOUCHSCREEN ? "touchscreen" : "touchpad", + sc->type == HMT_TYPE_TOUCHSCREEN ? "touchscreen" : "touchpad", nbuttons, nbuttons != 1 ? "s" : "", sc->is_clickpad ? ", click-pad" : ""); device_printf(sc->dev, - "%d contacts and [%s%s%s%s%s]. Report range [%d:%d] - [%d:%d]\n", - (int)sc->ai[WMT_SLOT].max + 1, - isset(sc->caps, WMT_IN_RANGE) ? "R" : "", - isset(sc->caps, WMT_CONFIDENCE) ? "C" : "", - isset(sc->caps, WMT_WIDTH) ? "W" : "", - isset(sc->caps, WMT_HEIGHT) ? "H" : "", - isset(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); + "%d contacts with [%s%s%s%s%s] properties. Report range [%d:%d] - [%d:%d]\n", + (int)sc->ai[HMT_SLOT].max + 1, + isset(sc->caps, HMT_IN_RANGE) ? "R" : "", + isset(sc->caps, HMT_CONFIDENCE) ? "C" : "", + isset(sc->caps, HMT_WIDTH) ? "W" : "", + isset(sc->caps, HMT_HEIGHT) ? "H" : "", + isset(sc->caps, HMT_PRESSURE) ? "P" : "", + (int)sc->ai[HMT_X].min, (int)sc->ai[HMT_Y].min, + (int)sc->ai[HMT_X].max, (int)sc->ai[HMT_Y].max); return (0); - -detach: - wmt_detach(dev); - return (ENXIO); } static int -wmt_detach(device_t dev) +hmt_detach(device_t dev) { - struct wmt_softc *sc = device_get_softc(dev); + struct hmt_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) +hmt_intr(void *context, void *buf, hid_size_t len) { + struct hmt_softc *sc = context; size_t usage; uint32_t *slot_data = sc->slot_data; uint32_t cont, btn; @@ -514,6 +474,37 @@ wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len) int32_t slot; uint32_t scan_time; int32_t delta; + uint8_t id; + + /* + * Special packet of zero length is generated by iichid driver running + * in polling mode at the start of inactivity period to workaround + * "stuck touch" problem caused by miss of finger release events. + * This snippet is to be removed after GPIO interrupt support is added. + */ + if (sc->iichid_sampling && len == 0) { + sc->prev_touch = false; + sc->timestamp = 0; + for (slot = 0; slot <= sc->ai[HMT_SLOT].max; slot++) { + evdev_push_abs(sc->evdev, ABS_MT_SLOT, slot); + evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1); + } + evdev_sync(sc->evdev); + return; + } + + /* Ignore irrelevant reports */ + id = sc->report_id != 0 ? *(uint8_t *)buf : 0; + if (sc->report_id != id) { + DPRINTF("Skip report with unexpected ID: %hhu\n", id); + return; + } + + /* Strip leading "report ID" byte */ + if (sc->report_id != 0) { + len--; + buf = (uint8_t *)buf + 1; + } /* * "In Parallel mode, devices report all contact information in a @@ -542,12 +533,12 @@ wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len) if (cont_count != 0) sc->nconts_todo = cont_count; -#ifdef USB_DEBUG +#ifdef HID_DEBUG DPRINTFN(6, "cont_count:%2u", (unsigned)cont_count); - 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); + if (hmt_debug >= 6) { + HMT_FOREACH_USAGE(sc->caps, usage) { + if (hmt_hid_map[usage].usage != HMT_NO_USAGE) + printf(" %-4s", hmt_hid_map[usage].name); } printf("\n"); } @@ -559,20 +550,20 @@ wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len) /* Use protocol Type B for reporting events */ for (cont = 0; cont < cont_count; cont++) { bzero(slot_data, sizeof(sc->slot_data)); - WMT_FOREACH_USAGE(sc->caps, usage) { + HMT_FOREACH_USAGE(sc->caps, usage) { if (sc->locs[cont][usage].size > 0) slot_data[usage] = hid_get_udata( buf, len, &sc->locs[cont][usage]); } slot = evdev_get_mt_slot_by_tracking_id(sc->evdev, - slot_data[WMT_CONTACTID]); + slot_data[HMT_CONTACTID]); -#ifdef USB_DEBUG +#ifdef HID_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) + if (hmt_debug >= 6) { + HMT_FOREACH_USAGE(sc->caps, usage) { + if (hmt_hid_map[usage].usage != HMT_NO_USAGE) printf("%04x ", slot_data[usage]); } printf("slot = %d\n", (int)slot); @@ -581,28 +572,28 @@ wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len) if (slot == -1) { DPRINTF("Slot overflow for contact_id %u\n", - (unsigned)slot_data[WMT_CONTACTID]); + (unsigned)slot_data[HMT_CONTACTID]); continue; } - if (slot_data[WMT_TIP_SWITCH] != 0 && - !(isset(sc->caps, WMT_CONFIDENCE) && - slot_data[WMT_CONFIDENCE] == 0)) { + if (slot_data[HMT_TIP_SWITCH] != 0 && + !(isset(sc->caps, HMT_CONFIDENCE) && + slot_data[HMT_CONFIDENCE] == 0)) { /* This finger is in proximity of the sensor */ sc->touch = true; - slot_data[WMT_SLOT] = slot; - slot_data[WMT_IN_RANGE] = !slot_data[WMT_IN_RANGE]; + slot_data[HMT_SLOT] = slot; + slot_data[HMT_IN_RANGE] = !slot_data[HMT_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) + width = slot_data[HMT_WIDTH] >> 1; + height = slot_data[HMT_HEIGHT] >> 1; + slot_data[HMT_ORIENTATION] = width > height; + slot_data[HMT_MAJOR] = MAX(width, height); + slot_data[HMT_MINOR] = MIN(width, height); + + HMT_FOREACH_USAGE(sc->caps, usage) + if (hmt_hid_map[usage].code != HMT_NO_CODE) evdev_push_abs(sc->evdev, - wmt_hid_map[usage].code, + hmt_hid_map[usage].code, slot_data[usage]); } else { evdev_push_abs(sc->evdev, ABS_MT_SLOT, slot); @@ -648,193 +639,80 @@ wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len) } } -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->report_len || - (len > 0 && sc->report_id != 0)) { - /* Limit report length to the maximum */ - if (len > (int)sc->report_len) - len = sc->report_len; - - usbd_copy_out(pc, 0, buf, len); - - /* Ignore irrelevant reports */ - if (sc->report_id && *buf != sc->report_id) - goto tr_ignore; - - /* Make sure we don't process old data */ - if (len < sc->report_len) - bzero(buf + len, sc->report_len - 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; - } -} - *** 408 LINES SKIPPED ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101072320.107NKpeN063149>