39#include <sys/kernel.h>
41#include <sys/malloc.h>
42#include <sys/module.h>
44#include <sys/stddef.h>
45#include <sys/sysctl.h>
48#include <dev/hid/hid.h>
58#include <dev/evdev/evdev.h>
59#include <dev/evdev/input.h>
61#define USB_DEBUG_VAR wmt_debug
64static SYSCTL_NODE(_hw_usb, OID_AUTO, wmt, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
65 "USB MSWindows 7/8/10 compatible Multi-touch Device");
67static int wmt_debug = 0;
69 &wmt_debug, 1,
"Debug level");
101 WMT_X = ABS_MT_INDEX(ABS_MT_POSITION_X),
102 WMT_Y = ABS_MT_INDEX(ABS_MT_POSITION_Y),
111#define WMT_N_USAGES MT_CNT
112#define WMT_NO_USAGE -1
124 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH),
130 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_WIDTH),
136 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_HEIGHT),
148 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
154 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
160 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID),
166 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_PRESSURE),
172 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_IN_RANGE),
178 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIDENCE),
184 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
190 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
251#define WMT_FOREACH_USAGE(caps, usage) \
252 for ((usage) = 0; (usage) < WMT_N_USAGES; ++(usage)) \
253 if (isset((caps), (usage)))
264#if __FreeBSD_version >= 1200077
265static evdev_open_t wmt_ev_open;
266static evdev_close_t wmt_ev_close;
273#if __FreeBSD_version >= 1200077
274 .ev_open = &wmt_ev_open,
275 .ev_close = &wmt_ev_close,
287 .flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
320 err = BUS_PROBE_DEFAULT;
327 DPRINTF(
"Input size invalid or too large: %d\n", sc->
isize);
363 DPRINTF(
"usbd_req_get_report error=(%s)\n",
366 DPRINTF(
"Feature report %hhu size invalid or too large: %u\n",
382 DPRINTF(
"usbd_req_get_report error=%d\n", err);
396 DPRINTF(
"Failed to set input mode: %d\n", err);
401 DPRINTF(
"Hardware reported %d contacts while only %d is "
409 mtx_init(&sc->
mtx,
"wmt lock", NULL, MTX_DEF);
418 sc->
evdev = evdev_alloc();
419 evdev_set_name(sc->
evdev, device_get_desc(
dev));
420 evdev_set_phys(sc->
evdev, device_get_nameunit(
dev));
425 evdev_set_flag(sc->
evdev, EVDEV_FLAG_MT_STCOMPAT);
428 evdev_support_prop(sc->
evdev, INPUT_PROP_DIRECT);
431 evdev_support_prop(sc->
evdev, INPUT_PROP_POINTER);
433 evdev_support_prop(sc->
evdev, INPUT_PROP_BUTTONPAD);
436 KASSERT(0, (
"wmt_attach: unsupported touch device type"));
438 evdev_support_event(sc->
evdev, EV_SYN);
439 evdev_support_event(sc->
evdev, EV_ABS);
441 evdev_support_event(sc->
evdev, EV_MSC);
442 evdev_support_msc(sc->
evdev, MSC_TIMESTAMP);
446 evdev_support_event(sc->
evdev, EV_KEY);
448 evdev_support_key(sc->
evdev, BTN_LEFT);
451 evdev_support_key(sc->
evdev, BTN_MOUSE + btn);
456 evdev_support_abs(sc->
evdev,
460 evdev_support_abs(sc->
evdev, ABS_MT_FIRST + i,
464 err = evdev_register_mtx(sc->
evdev, &sc->
mtx);
469 device_printf(sc->
dev,
"Multitouch %s with %d external button%s%s\n",
471 nbuttons, nbuttons != 1 ?
"s" :
"",
473 device_printf(sc->
dev,
474 "%d contacts and [%s%s%s%s%s]. Report range [%d:%d] - [%d:%d]\n",
496 evdev_free(sc->
evdev);
498 mtx_destroy(&sc->
mtx);
506 union evdev_mt_slot *slot_data;
511 uint32_t int_btn = 0;
512 uint32_t left_btn = 0;
545 DPRINTFN(6,
"cont_count:%2u", (
unsigned)cont_count);
546 if (wmt_debug >= 6) {
559 for (cont = 0; cont < cont_count; cont++) {
563 if (sc->
locs[cont][usage].size > 0)
564 slot_data->val[usage] = hid_get_udata(
565 buf,
len, &sc->
locs[cont][usage]);
568 slot = evdev_mt_id_to_slot(sc->
evdev, slot_data->id);
571 DPRINTFN(6,
"cont%01x: data = ", cont);
572 if (wmt_debug >= 6) {
575 printf(
"%04x ", slot_data->val[usage]);
577 printf(
"slot = %d\n",
slot);
582 DPRINTF(
"Slot overflow for contact_id %u\n",
583 (
unsigned)slot_data->id);
596 slot_data->ori =
width > height;
597 slot_data->maj = MAX(
width, height);
598 slot_data->min = MIN(
width, height);
602 evdev_mt_push_slot(sc->
evdev,
slot, slot_data);
628 left_btn = hid_get_data(buf,
len, &sc->
btn_loc[0]);
630 evdev_push_key(sc->
evdev, BTN_LEFT,
631 (int_btn != 0) | (left_btn != 0));
634 evdev_push_key(sc->
evdev, BTN_MOUSE + btn,
639 evdev_sync(sc->
evdev);
648 uint8_t *buf = sc->buf;
657 DPRINTFN(6,
"sc=%p actlen=%d\n", sc,
len);
672 if (len < sc->report_len)
707 mtx_assert(&sc->
mtx, MA_OWNED);
716 mtx_assert(&sc->
mtx, MA_OWNED);
722#if __FreeBSD_version >= 1200077
724wmt_ev_close(
struct evdev_dev *
evdev)
734wmt_ev_open(
struct evdev_dev *
evdev)
751 uint32_t left_btn, btn;
752 int32_t cont_count_max = 0;
753 uint8_t report_id = 0;
754 bool touch_coll =
false;
755 bool finger_coll =
false;
756 bool cont_count_found =
false;
757 bool scan_time_found =
false;
758 bool has_int_button =
false;
760#define WMT_HI_ABSOLUTE(hi) \
761 (((hi).flags & (HIO_CONST|HIO_VARIABLE|HIO_RELATIVE)) == HIO_VARIABLE)
762#define HUMS_THQA_CERT 0xC5
765 hd = hid_start_parse(d_ptr, d_len, 1 << hid_feature);
766 while (hid_get_item(hd, &hi)) {
769 if (hi.collevel == 1 && hi.usage ==
770 HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN)) {
776 if (hi.collevel == 1 && hi.usage ==
777 HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD)) {
783 case hid_endcollection:
784 if (hi.collevel == 0 && touch_coll)
788 if (hi.collevel == 1 && touch_coll && hi.usage ==
793 if (hi.collevel == 1 && touch_coll && hi.usage ==
794 HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX)) {
795 cont_count_max = hi.logical_maximum;
800 if (hi.collevel == 1 && touch_coll && hi.usage ==
801 HID_USAGE2(HUP_DIGITIZERS, HUD_BUTTON_TYPE)) {
821 hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
822 while (hid_get_item(hd, &hi)) {
825 if (hi.collevel == 1 && hi.usage ==
826 HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))
828 else if (touch_coll && hi.collevel == 2 &&
829 (report_id == 0 || report_id == hi.report_ID) &&
830 hi.usage == HID_USAGE2(HUP_DIGITIZERS, HUD_FINGER))
833 case hid_endcollection:
834 if (hi.collevel == 1 && finger_coll) {
837 }
else if (hi.collevel == 0 && touch_coll)
846 (report_id == 0 || report_id == hi.report_ID))
847 report_id = hi.report_ID;
851 if (hi.collevel == 1 && left_btn == 2 &&
852 hi.usage == HID_USAGE2(HUP_BUTTON, 1)) {
853 has_int_button =
true;
857 if (hi.collevel == 1 &&
858 hi.usage >= HID_USAGE2(HUP_BUTTON, left_btn) &&
860 btn = (hi.usage & 0xFFFF) - left_btn;
867 if (hi.collevel == 1 && hi.usage ==
868 HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTCOUNT)) {
869 cont_count_found =
true;
874 if (hi.collevel == 1 && hi.usage ==
875 HID_USAGE2(HUP_DIGITIZERS, HUD_SCAN_TIME)) {
876 scan_time_found =
true;
882 if (!finger_coll || hi.collevel != 2)
884 if (cont >= MAX_MT_SLOTS) {
885 DPRINTF(
"Finger %zu ignored\n", cont);
897 if (sc->
locs[cont][i].size)
899 sc->
locs[cont][i] = hi.loc;
909 .
max = hi.logical_maximum,
910 .min = hi.logical_minimum,
911 .res = hid_item_resolution(&hi),
924 if (!cont_count_found || !scan_time_found || cont == 0)
940 if (cont_count_max < 1)
941 cont_count_max = cont;
949 sc->
isize = hid_report_size_max(d_ptr, d_len, hid_input, NULL);
950 sc->
report_len = hid_report_size(d_ptr, d_len, hid_input,
952 sc->
cont_max_rlen = hid_report_size(d_ptr, d_len, hid_feature,
976 DPRINTF(
"Feature report %hhu size invalid or too large: %u\n",
SYSCTL_INT(_hw_usb_dwc_otg, OID_AUTO, phy_type, CTLFLAG_RDTUN, &dwc_otg_phy_type, 0, "DWC OTG PHY TYPE - 0/1/2/3 - ULPI/HSIC/INTERNAL/UTMI+")
enum usb_hc_mode usb_mode
struct usbd_lookup_info info
struct usb_device * device
uint8_t buf[WMT_BSIZE] __aligned(4)
struct hid_location cont_max_loc
union evdev_mt_slot slot_data
struct wmt_absinfo ai[WMT_N_USAGES]
uint32_t nconts_per_report
struct hid_location btn_type_loc
struct hid_location btn_loc[WMT_BTN_MAX]
struct hid_location scan_time_loc
struct usb_xfer * xfer[WMT_N_TRANSFER]
struct hid_location int_btn_loc
struct hid_location cont_count_loc
struct hid_location locs[MAX_MT_SLOTS][WMT_N_USAGES]
uint8_t buttons[howmany(WMT_BTN_MAX, 8)]
uint8_t caps[howmany(WMT_N_USAGES, 8)]
struct hid_location input_mode_loc
void usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, void *ptr, usb_frlength_t len)
const char * usb_get_serial(struct usb_device *udev)
const char * usbd_errstr(usb_error_t err)
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)
uint8_t usb_test_quirk(const struct usb_attach_arg *uaa, uint16_t quirk)
usb_error_t usbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
usb_error_t usbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
void usbd_transfer_submit(struct usb_xfer *xfer)
void usbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup)
void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex, usb_frlength_t len)
struct usb_page_cache * usbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex)
usb_error_t usbd_transfer_setup(struct usb_device *udev, const uint8_t *ifaces, struct usb_xfer **ppxfer, const struct usb_config *setup_start, uint16_t n_setup, void *priv_sc, struct mtx *xfer_mtx)
void usbd_transfer_start(struct usb_xfer *xfer)
void * usbd_xfer_softc(struct usb_xfer *xfer)
void usbd_xfer_set_stall(struct usb_xfer *xfer)
void usbd_transfer_stop(struct usb_xfer *xfer)
void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes, int *nframes)
void device_set_usb_desc(device_t dev)
#define USB_IFACE_SUBCLASS(isc)
@ USB_ERR_NORMAL_COMPLETION
#define USB_IFACE_CLASS(ic)
#define USB_ST_TRANSFERRED
void() usb_callback_t(struct usb_xfer *, usb_error_t)
#define STRUCT_USB_HOST_ID
#define USB_GET_STATE(xfer)
#define UHID_FEATURE_REPORT
static evdev_close_t wmt_ev_close_11
static int wmt_set_input_mode(struct wmt_softc *, enum wmt_input_mode)
DRIVER_MODULE(wmt, uhub, wmt_driver, wmt_devclass, NULL, 0)
static device_attach_t wmt_attach
static devclass_t wmt_devclass
static const STRUCT_USB_HOST_ID wmt_devs[]
static const struct usb_config wmt_config[WMT_N_TRANSFER]
static usb_callback_t wmt_intr_callback
USB_PNP_HOST_INFO(wmt_devs)
MODULE_DEPEND(wmt, usb, 1, 1, 1)
static device_method_t wmt_methods[]
static const struct evdev_methods wmt_evdev_methods
static void wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len)
#define WMT_FOREACH_USAGE(caps, usage)
static device_probe_t wmt_probe
#define WMT_HI_ABSOLUTE(hi)
static SYSCTL_NODE(_hw_usb, OID_AUTO, wmt, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "USB MSWindows 7/8/10 compatible Multi-touch Device")
static driver_t wmt_driver
@ WMT_INPUT_MODE_MT_TOUCHPAD
@ WMT_INPUT_MODE_MT_TOUCHSCREEN
SYSCTL_BOOL(_hw_usb_wmt, OID_AUTO, timestamps, CTLFLAG_RDTUN, &wmt_timestamps, 1, "Enable hardware timestamp reporting")
static enum wmt_type wmt_hid_parse(struct wmt_softc *, const void *, uint16_t)
static const struct wmt_hid_map_item wmt_hid_map[WMT_N_USAGES]
static device_detach_t wmt_detach
static evdev_open_t wmt_ev_open_11
static bool wmt_timestamps