xref: /freebsd/sys/dev/usb/input/wmt.c (revision 9768746b)
1 /*-
2  * Copyright (c) 2014-2017 Vladimir Kondratyev <wulf@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 /*
31  * MS Windows 7/8/10 compatible USB HID Multi-touch Device driver.
32  * https://msdn.microsoft.com/en-us/library/windows/hardware/jj151569(v=vs.85).aspx
33  * https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
34  */
35 
36 #include <sys/param.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/kernel.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/module.h>
43 #include <sys/mutex.h>
44 #include <sys/stddef.h>
45 #include <sys/sysctl.h>
46 #include <sys/systm.h>
47 
48 #include <dev/hid/hid.h>
49 
50 #include "usbdevs.h"
51 #include <dev/usb/usb.h>
52 #include <dev/usb/usbdi.h>
53 #include <dev/usb/usbdi_util.h>
54 #include <dev/usb/usbhid.h>
55 
56 #include <dev/usb/quirk/usb_quirk.h>
57 
58 #include <dev/evdev/evdev.h>
59 #include <dev/evdev/input.h>
60 
61 #define	USB_DEBUG_VAR wmt_debug
62 #include <dev/usb/usb_debug.h>
63 
64 static SYSCTL_NODE(_hw_usb, OID_AUTO, wmt, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
65     "USB MSWindows 7/8/10 compatible Multi-touch Device");
66 #ifdef USB_DEBUG
67 static int wmt_debug = 0;
68 SYSCTL_INT(_hw_usb_wmt, OID_AUTO, debug, CTLFLAG_RWTUN,
69     &wmt_debug, 1, "Debug level");
70 #endif
71 static bool wmt_timestamps = 0;
72 SYSCTL_BOOL(_hw_usb_wmt, OID_AUTO, timestamps, CTLFLAG_RDTUN,
73     &wmt_timestamps, 1, "Enable hardware timestamp reporting");
74 
75 #define	WMT_BSIZE	1024	/* bytes, buffer size */
76 #define	WMT_BTN_MAX	8	/* Number of buttons supported */
77 
78 enum {
79 	WMT_INTR_DT,
80 	WMT_N_TRANSFER,
81 };
82 
83 enum wmt_type {
84 	WMT_TYPE_UNKNOWN = 0,	/* HID report descriptor is not probed */
85 	WMT_TYPE_UNSUPPORTED,	/* Repdescr does not belong to MT device */
86 	WMT_TYPE_TOUCHPAD,
87 	WMT_TYPE_TOUCHSCREEN,
88 };
89 
90 enum wmt_input_mode {
91 	WMT_INPUT_MODE_MOUSE =		0x0,
92 	WMT_INPUT_MODE_MT_TOUCHSCREEN =	0x2,
93 	WMT_INPUT_MODE_MT_TOUCHPAD =	0x3,
94 };
95 
96 enum {
97 	WMT_TIP_SWITCH =	ABS_MT_INDEX(ABS_MT_TOOL_TYPE),
98 	WMT_WIDTH =		ABS_MT_INDEX(ABS_MT_TOUCH_MAJOR),
99 	WMT_HEIGHT =		ABS_MT_INDEX(ABS_MT_TOUCH_MINOR),
100 	WMT_ORIENTATION =	ABS_MT_INDEX(ABS_MT_ORIENTATION),
101 	WMT_X =			ABS_MT_INDEX(ABS_MT_POSITION_X),
102 	WMT_Y =			ABS_MT_INDEX(ABS_MT_POSITION_Y),
103 	WMT_CONTACTID =		ABS_MT_INDEX(ABS_MT_TRACKING_ID),
104 	WMT_PRESSURE =		ABS_MT_INDEX(ABS_MT_PRESSURE),
105 	WMT_IN_RANGE =		ABS_MT_INDEX(ABS_MT_DISTANCE),
106 	WMT_CONFIDENCE =	ABS_MT_INDEX(ABS_MT_BLOB_ID),
107 	WMT_TOOL_X =		ABS_MT_INDEX(ABS_MT_TOOL_X),
108 	WMT_TOOL_Y =		ABS_MT_INDEX(ABS_MT_TOOL_Y),
109 };
110 
111 #define	WMT_N_USAGES	MT_CNT
112 #define	WMT_NO_USAGE	-1
113 
114 struct wmt_hid_map_item {
115 	char		name[5];
116 	int32_t 	usage;		/* HID usage */
117 	bool		reported;	/* Item value is passed to evdev */
118 	bool		required;	/* Required for MT Digitizers */
119 };
120 
121 static const struct wmt_hid_map_item wmt_hid_map[WMT_N_USAGES] = {
122 	[WMT_TIP_SWITCH] = {
123 		.name = "TIP",
124 		.usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH),
125 		.reported = false,
126 		.required = true,
127 	},
128 	[WMT_WIDTH] = {
129 		.name = "WDTH",
130 		.usage = HID_USAGE2(HUP_DIGITIZERS, HUD_WIDTH),
131 		.reported = true,
132 		.required = false,
133 	},
134 	[WMT_HEIGHT] = {
135 		.name = "HGHT",
136 		.usage = HID_USAGE2(HUP_DIGITIZERS, HUD_HEIGHT),
137 		.reported = true,
138 		.required = false,
139 	},
140 	[WMT_ORIENTATION] = {
141 		.name = "ORIE",
142 		.usage = WMT_NO_USAGE,
143 		.reported = true,
144 		.required = false,
145 	},
146 	[WMT_X] = {
147 		.name = "X",
148 		.usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
149 		.reported = true,
150 		.required = true,
151 	},
152 	[WMT_Y] = {
153 		.name = "Y",
154 		.usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
155 		.reported = true,
156 		.required = true,
157 	},
158 	[WMT_CONTACTID] = {
159 		.name = "C_ID",
160 		.usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID),
161 		.reported = true,
162 		.required = true,
163 	},
164 	[WMT_PRESSURE] = {
165 		.name = "PRES",
166 		.usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_PRESSURE),
167 		.reported = true,
168 		.required = false,
169 	},
170 	[WMT_IN_RANGE] = {
171 		.name = "RANG",
172 		.usage = HID_USAGE2(HUP_DIGITIZERS, HUD_IN_RANGE),
173 		.reported = true,
174 		.required = false,
175 	},
176 	[WMT_CONFIDENCE] = {
177 		.name = "CONF",
178 		.usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIDENCE),
179 		.reported = false,
180 		.required = false,
181 	},
182 	[WMT_TOOL_X] = {	/* Shares HID usage with WMT_X */
183 		.name = "TL_X",
184 		.usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
185 		.reported = true,
186 		.required = false,
187 	},
188 	[WMT_TOOL_Y] = {	/* Shares HID usage with WMT_Y */
189 		.name = "TL_Y",
190 		.usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
191 		.reported = true,
192 		.required = false,
193 	},
194 };
195 
196 struct wmt_absinfo {
197 	int32_t			min;
198 	int32_t			max;
199 	int32_t			res;
200 };
201 
202 struct wmt_softc {
203 	device_t		dev;
204 	enum wmt_type		type;
205 
206 	int32_t			cont_count_max;
207 	struct mtx		mtx;
208 	struct wmt_absinfo	ai[WMT_N_USAGES];
209 	struct hid_location	locs[MAX_MT_SLOTS][WMT_N_USAGES];
210 	struct hid_location	cont_count_loc;
211 	struct hid_location	btn_loc[WMT_BTN_MAX];
212 	struct hid_location	int_btn_loc;
213 	struct hid_location	scan_time_loc;
214 	int32_t			scan_time_max;
215 	int32_t			scan_time;
216 	int32_t			timestamp;
217 	bool			touch;
218 	bool			prev_touch;
219 
220 	struct usb_xfer		*xfer[WMT_N_TRANSFER];
221 	struct evdev_dev	*evdev;
222 
223 	union evdev_mt_slot	slot_data;
224 	uint8_t			caps[howmany(WMT_N_USAGES, 8)];
225 	uint8_t			buttons[howmany(WMT_BTN_MAX, 8)];
226 	uint32_t		isize;
227 	uint32_t		nconts_per_report;
228 	uint32_t		nconts_todo;
229 	uint32_t		report_len;
230 	uint8_t			report_id;
231 	uint32_t		max_button;
232 	bool			has_int_button;
233 	bool			is_clickpad;
234 	bool			do_timestamps;
235 
236 	struct hid_location	cont_max_loc;
237 	uint32_t		cont_max_rlen;
238 	uint8_t			cont_max_rid;
239 	struct hid_location	btn_type_loc;
240 	uint32_t		btn_type_rlen;
241 	uint8_t			btn_type_rid;
242 	uint32_t		thqa_cert_rlen;
243 	uint8_t			thqa_cert_rid;
244 	struct hid_location	input_mode_loc;
245 	uint32_t		input_mode_rlen;
246 	uint8_t			input_mode_rid;
247 
248 	uint8_t			buf[WMT_BSIZE] __aligned(4);
249 };
250 
251 #define	WMT_FOREACH_USAGE(caps, usage)			\
252 	for ((usage) = 0; (usage) < WMT_N_USAGES; ++(usage))	\
253 		if (isset((caps), (usage)))
254 
255 static enum wmt_type wmt_hid_parse(struct wmt_softc *, const void *, uint16_t);
256 static int wmt_set_input_mode(struct wmt_softc *, enum wmt_input_mode);
257 
258 static usb_callback_t	wmt_intr_callback;
259 
260 static device_probe_t	wmt_probe;
261 static device_attach_t	wmt_attach;
262 static device_detach_t	wmt_detach;
263 
264 static evdev_open_t	wmt_ev_open;
265 static evdev_close_t	wmt_ev_close;
266 
267 static const struct evdev_methods wmt_evdev_methods = {
268 	.ev_open = &wmt_ev_open,
269 	.ev_close = &wmt_ev_close,
270 };
271 
272 static const struct usb_config wmt_config[WMT_N_TRANSFER] = {
273 	[WMT_INTR_DT] = {
274 		.type = UE_INTERRUPT,
275 		.endpoint = UE_ADDR_ANY,
276 		.direction = UE_DIR_IN,
277 		.flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
278 		.bufsize = WMT_BSIZE,
279 		.callback = &wmt_intr_callback,
280 	},
281 };
282 
283 static int
284 wmt_probe(device_t dev)
285 {
286 	struct usb_attach_arg *uaa = device_get_ivars(dev);
287 	struct wmt_softc *sc = device_get_softc(dev);
288 	void *d_ptr;
289 	uint16_t d_len;
290 	int err;
291 
292 	if (uaa->usb_mode != USB_MODE_HOST)
293 		return (ENXIO);
294 
295 	if (uaa->info.bInterfaceClass != UICLASS_HID)
296 		return (ENXIO);
297 
298 	if (usb_test_quirk(uaa, UQ_WMT_IGNORE))
299 		return (ENXIO);
300 
301 	err = usbd_req_get_hid_desc(uaa->device, NULL,
302 	    &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
303 	if (err)
304 		return (ENXIO);
305 
306 	/* Check if report descriptor belongs to a HID multitouch device */
307 	if (sc->type == WMT_TYPE_UNKNOWN)
308 		sc->type = wmt_hid_parse(sc, d_ptr, d_len);
309 	if (sc->type != WMT_TYPE_UNSUPPORTED)
310 		err = BUS_PROBE_DEFAULT;
311 	else
312 		err = ENXIO;
313 
314 	/* Check HID report length */
315 	if (sc->type != WMT_TYPE_UNSUPPORTED &&
316 	    (sc->isize <= 0 || sc->isize > WMT_BSIZE)) {
317 		DPRINTF("Input size invalid or too large: %d\n", sc->isize);
318 		err = ENXIO;
319 	}
320 
321 	free(d_ptr, M_TEMP);
322 	return (err);
323 }
324 
325 static int
326 wmt_attach(device_t dev)
327 {
328 	struct usb_attach_arg *uaa = device_get_ivars(dev);
329 	struct wmt_softc *sc = device_get_softc(dev);
330 	uint32_t cont_count_max;
331 	int nbuttons, btn;
332 	size_t i;
333 	int err;
334 
335 	device_set_usb_desc(dev);
336 	sc->dev = dev;
337 
338 	/* Fetch and parse "Contact count maximum" feature report */
339 	if (sc->cont_max_rlen > 0 && sc->cont_max_rlen <= WMT_BSIZE) {
340 		err = usbd_req_get_report(uaa->device, NULL, sc->buf,
341 		    sc->cont_max_rlen, uaa->info.bIfaceIndex,
342 		    UHID_FEATURE_REPORT, sc->cont_max_rid);
343 		if (err == USB_ERR_NORMAL_COMPLETION) {
344 			cont_count_max = hid_get_udata(sc->buf + 1,
345 			    sc->cont_max_rlen - 1, &sc->cont_max_loc);
346 			/*
347 			 * Feature report is a primary source of
348 			 * 'Contact Count Maximum'
349 			 */
350 			if (cont_count_max > 0)
351 				sc->cont_count_max = cont_count_max;
352 		} else
353 			DPRINTF("usbd_req_get_report error=(%s)\n",
354 			    usbd_errstr(err));
355 	} else
356 		DPRINTF("Feature report %hhu size invalid or too large: %u\n",
357 		    sc->cont_max_rid, sc->cont_max_rlen);
358 
359 	/* Fetch and parse "Button type" feature report */
360 	if (sc->btn_type_rlen > 1 && sc->btn_type_rlen <= WMT_BSIZE &&
361 	    sc->btn_type_rid != sc->cont_max_rid) {
362 		bzero(sc->buf, sc->btn_type_rlen);
363 		err = usbd_req_get_report(uaa->device, NULL, sc->buf,
364 		    sc->btn_type_rlen, uaa->info.bIfaceIndex,
365 		    UHID_FEATURE_REPORT, sc->btn_type_rid);
366 	}
367 	if (sc->btn_type_rlen > 1) {
368 		if (err == 0)
369 			sc->is_clickpad = hid_get_udata(sc->buf + 1,
370 			    sc->btn_type_rlen - 1, &sc->btn_type_loc) == 0;
371 		else
372 			DPRINTF("usbd_req_get_report error=%d\n", err);
373 	}
374 
375 	/* Fetch THQA certificate to enable some devices like WaveShare */
376 	if (sc->thqa_cert_rlen > 0 && sc->thqa_cert_rlen <= WMT_BSIZE &&
377 	    sc->thqa_cert_rid != sc->cont_max_rid)
378 		(void)usbd_req_get_report(uaa->device, NULL, sc->buf,
379 		    sc->thqa_cert_rlen, uaa->info.bIfaceIndex,
380 		    UHID_FEATURE_REPORT, sc->thqa_cert_rid);
381 
382 	/* Switch touchpad in to absolute multitouch mode */
383 	if (sc->type == WMT_TYPE_TOUCHPAD) {
384 		err = wmt_set_input_mode(sc, WMT_INPUT_MODE_MT_TOUCHPAD);
385 		if (err != 0)
386 			DPRINTF("Failed to set input mode: %d\n", err);
387 	}
388 
389 	/* Cap contact count maximum to MAX_MT_SLOTS */
390 	if (sc->cont_count_max > MAX_MT_SLOTS) {
391 		DPRINTF("Hardware reported %d contacts while only %d is "
392 		    "supported\n", (int)sc->cont_count_max, MAX_MT_SLOTS);
393 		sc->cont_count_max = MAX_MT_SLOTS;
394 	}
395 
396 	if (/*usb_test_quirk(hw, UQ_MT_TIMESTAMP) ||*/ wmt_timestamps)
397 		sc->do_timestamps = true;
398 
399 	mtx_init(&sc->mtx, "wmt lock", NULL, MTX_DEF);
400 
401 	err = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
402 	    sc->xfer, wmt_config, WMT_N_TRANSFER, sc, &sc->mtx);
403 	if (err != USB_ERR_NORMAL_COMPLETION) {
404 		DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err));
405 		goto detach;
406 	}
407 
408 	sc->evdev = evdev_alloc();
409 	evdev_set_name(sc->evdev, device_get_desc(dev));
410 	evdev_set_phys(sc->evdev, device_get_nameunit(dev));
411 	evdev_set_id(sc->evdev, BUS_USB, uaa->info.idVendor,
412 	    uaa->info.idProduct, 0);
413 	evdev_set_serial(sc->evdev, usb_get_serial(uaa->device));
414 	evdev_set_methods(sc->evdev, sc, &wmt_evdev_methods);
415 	evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT);
416 	switch (sc->type) {
417 	case WMT_TYPE_TOUCHSCREEN:
418 		evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT);
419 		break;
420 	case WMT_TYPE_TOUCHPAD:
421 		evdev_support_prop(sc->evdev, INPUT_PROP_POINTER);
422 		if (sc->is_clickpad)
423 			evdev_support_prop(sc->evdev, INPUT_PROP_BUTTONPAD);
424 		break;
425 	default:
426 		KASSERT(0, ("wmt_attach: unsupported touch device type"));
427 	}
428 	evdev_support_event(sc->evdev, EV_SYN);
429 	evdev_support_event(sc->evdev, EV_ABS);
430 	if (sc->do_timestamps) {
431 		evdev_support_event(sc->evdev, EV_MSC);
432 		evdev_support_msc(sc->evdev, MSC_TIMESTAMP);
433 	}
434 	nbuttons = 0;
435 	if (sc->max_button != 0 || sc->has_int_button) {
436 		evdev_support_event(sc->evdev, EV_KEY);
437 		if (sc->has_int_button)
438 			evdev_support_key(sc->evdev, BTN_LEFT);
439 		for (btn = 0; btn < sc->max_button; ++btn) {
440 			if (isset(sc->buttons, btn)) {
441 				evdev_support_key(sc->evdev, BTN_MOUSE + btn);
442 				nbuttons++;
443 			}
444 		}
445 	}
446 	evdev_support_abs(sc->evdev,
447 	    ABS_MT_SLOT, 0, sc->cont_count_max - 1, 0, 0, 0);
448 	WMT_FOREACH_USAGE(sc->caps, i) {
449 		if (wmt_hid_map[i].reported)
450 			evdev_support_abs(sc->evdev, ABS_MT_FIRST + i,
451 			    sc->ai[i].min, sc->ai[i].max, 0, 0, sc->ai[i].res);
452 	}
453 
454 	err = evdev_register_mtx(sc->evdev, &sc->mtx);
455 	if (err)
456 		goto detach;
457 
458 	/* Announce information about the touch device */
459 	device_printf(sc->dev, "Multitouch %s with %d external button%s%s\n",
460 	    sc->type == WMT_TYPE_TOUCHSCREEN ? "touchscreen" : "touchpad",
461 	    nbuttons, nbuttons != 1 ? "s" : "",
462 	    sc->is_clickpad ? ", click-pad" : "");
463 	device_printf(sc->dev,
464 	    "%d contacts and [%s%s%s%s%s]. Report range [%d:%d] - [%d:%d]\n",
465 	    (int)sc->cont_count_max,
466 	    isset(sc->caps, WMT_IN_RANGE) ? "R" : "",
467 	    isset(sc->caps, WMT_CONFIDENCE) ? "C" : "",
468 	    isset(sc->caps, WMT_WIDTH) ? "W" : "",
469 	    isset(sc->caps, WMT_HEIGHT) ? "H" : "",
470 	    isset(sc->caps, WMT_PRESSURE) ? "P" : "",
471 	    (int)sc->ai[WMT_X].min, (int)sc->ai[WMT_Y].min,
472 	    (int)sc->ai[WMT_X].max, (int)sc->ai[WMT_Y].max);
473 
474 	return (0);
475 
476 detach:
477 	wmt_detach(dev);
478 	return (ENXIO);
479 }
480 
481 static int
482 wmt_detach(device_t dev)
483 {
484 	struct wmt_softc *sc = device_get_softc(dev);
485 
486 	evdev_free(sc->evdev);
487 	usbd_transfer_unsetup(sc->xfer, WMT_N_TRANSFER);
488 	mtx_destroy(&sc->mtx);
489 	return (0);
490 }
491 
492 static void
493 wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len)
494 {
495 	size_t usage;
496 	union evdev_mt_slot *slot_data;
497 	uint32_t cont, btn;
498 	uint32_t cont_count;
499 	uint32_t width;
500 	uint32_t height;
501 	uint32_t int_btn = 0;
502 	uint32_t left_btn = 0;
503 	int slot;
504 	uint32_t scan_time;
505 	int32_t delta;
506 
507 	/*
508 	 * "In Parallel mode, devices report all contact information in a
509 	 * single packet. Each physical contact is represented by a logical
510 	 * collection that is embedded in the top-level collection."
511 	 *
512 	 * Since additional contacts that were not present will still be in the
513 	 * report with contactid=0 but contactids are zero-based, find
514 	 * contactcount first.
515 	 */
516 	cont_count = hid_get_udata(buf, len, &sc->cont_count_loc);
517 	/*
518 	 * "In Hybrid mode, the number of contacts that can be reported in one
519 	 * report is less than the maximum number of contacts that the device
520 	 * supports. For example, a device that supports a maximum of
521 	 * 4 concurrent physical contacts, can set up its top-level collection
522 	 * to deliver a maximum of two contacts in one report. If four contact
523 	 * points are present, the device can break these up into two serial
524 	 * reports that deliver two contacts each.
525 	 *
526 	 * "When a device delivers data in this manner, the Contact Count usage
527 	 * value in the first report should reflect the total number of
528 	 * contacts that are being delivered in the hybrid reports. The other
529 	 * serial reports should have a contact count of zero (0)."
530 	 */
531 	if (cont_count != 0)
532 		sc->nconts_todo = cont_count;
533 
534 #ifdef USB_DEBUG
535 	DPRINTFN(6, "cont_count:%2u", (unsigned)cont_count);
536 	if (wmt_debug >= 6) {
537 		WMT_FOREACH_USAGE(sc->caps, usage) {
538 			if (wmt_hid_map[usage].usage != WMT_NO_USAGE)
539 				printf(" %-4s", wmt_hid_map[usage].name);
540 		}
541 		printf("\n");
542 	}
543 #endif
544 
545 	/* Find the number of contacts reported in current report */
546 	cont_count = MIN(sc->nconts_todo, sc->nconts_per_report);
547 
548 	/* Use protocol Type B for reporting events */
549 	for (cont = 0; cont < cont_count; cont++) {
550 		slot_data = &sc->slot_data;
551 		bzero(slot_data, sizeof(sc->slot_data));
552 		WMT_FOREACH_USAGE(sc->caps, usage) {
553 			if (sc->locs[cont][usage].size > 0)
554 				slot_data->val[usage] = hid_get_udata(
555 				    buf, len, &sc->locs[cont][usage]);
556 		}
557 
558 		slot = evdev_mt_id_to_slot(sc->evdev, slot_data->id);
559 
560 #ifdef USB_DEBUG
561 		DPRINTFN(6, "cont%01x: data = ", cont);
562 		if (wmt_debug >= 6) {
563 			WMT_FOREACH_USAGE(sc->caps, usage) {
564 				if (wmt_hid_map[usage].usage != WMT_NO_USAGE)
565 					printf("%04x ", slot_data->val[usage]);
566 			}
567 			printf("slot = %d\n", slot);
568 		}
569 #endif
570 
571 		if (slot == -1) {
572 			DPRINTF("Slot overflow for contact_id %u\n",
573 			    (unsigned)slot_data->id);
574 			continue;
575 		}
576 
577 		if (slot_data->val[WMT_TIP_SWITCH] != 0 &&
578 		    !(isset(sc->caps, WMT_CONFIDENCE) &&
579 		      slot_data->val[WMT_CONFIDENCE] == 0)) {
580 			/* This finger is in proximity of the sensor */
581 			sc->touch = true;
582 			slot_data->dist = !slot_data->val[WMT_IN_RANGE];
583 			/* Divided by two to match visual scale of touch */
584 			width = slot_data->val[WMT_WIDTH] >> 1;
585 			height = slot_data->val[WMT_HEIGHT] >> 1;
586 			slot_data->ori = width > height;
587 			slot_data->maj = MAX(width, height);
588 			slot_data->min = MIN(width, height);
589 		} else
590 			slot_data = NULL;
591 
592 		evdev_mt_push_slot(sc->evdev, slot, slot_data);
593 	}
594 
595 	sc->nconts_todo -= cont_count;
596 	if (sc->do_timestamps && sc->nconts_todo == 0) {
597 		/* HUD_SCAN_TIME is measured in 100us, convert to us. */
598 		scan_time = hid_get_udata(buf, len, &sc->scan_time_loc);
599 		if (sc->prev_touch) {
600 			delta = scan_time - sc->scan_time;
601 			if (delta < 0)
602 				delta += sc->scan_time_max;
603 		} else
604 			delta = 0;
605 		sc->scan_time = scan_time;
606 		sc->timestamp += delta * 100;
607 		evdev_push_msc(sc->evdev, MSC_TIMESTAMP, sc->timestamp);
608 		sc->prev_touch = sc->touch;
609 		sc->touch = false;
610 		if (!sc->prev_touch)
611 			sc->timestamp = 0;
612 	}
613 	if (sc->nconts_todo == 0) {
614 		/* Report both the click and external left btns as BTN_LEFT */
615 		if (sc->has_int_button)
616 			int_btn = hid_get_data(buf, len, &sc->int_btn_loc);
617 		if (isset(sc->buttons, 0))
618 			left_btn = hid_get_data(buf, len, &sc->btn_loc[0]);
619 		if (sc->has_int_button || isset(sc->buttons, 0))
620 			evdev_push_key(sc->evdev, BTN_LEFT,
621 			    (int_btn != 0) | (left_btn != 0));
622 		for (btn = 1; btn < sc->max_button; ++btn) {
623 			if (isset(sc->buttons, btn))
624 				evdev_push_key(sc->evdev, BTN_MOUSE + btn,
625 				    hid_get_data(buf,
626 						 len,
627 						 &sc->btn_loc[btn]) != 0);
628 		}
629 		evdev_sync(sc->evdev);
630 	}
631 }
632 
633 static void
634 wmt_intr_callback(struct usb_xfer *xfer, usb_error_t error)
635 {
636 	struct wmt_softc *sc = usbd_xfer_softc(xfer);
637 	struct usb_page_cache *pc;
638 	uint8_t *buf = sc->buf;
639 	int len;
640 
641 	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
642 
643 	switch (USB_GET_STATE(xfer)) {
644 	case USB_ST_TRANSFERRED:
645 		pc = usbd_xfer_get_frame(xfer, 0);
646 
647 		DPRINTFN(6, "sc=%p actlen=%d\n", sc, len);
648 
649 		if (len >= (int)sc->report_len ||
650 		    (len > 0 && sc->report_id != 0)) {
651 			/* Limit report length to the maximum */
652 			if (len > (int)sc->report_len)
653 				len = sc->report_len;
654 
655 			usbd_copy_out(pc, 0, buf, len);
656 
657 			/* Ignore irrelevant reports */
658 			if (sc->report_id && *buf != sc->report_id)
659 				goto tr_ignore;
660 
661 			/* Make sure we don't process old data */
662 			if (len < sc->report_len)
663 				bzero(buf + len, sc->report_len - len);
664 
665 			/* Strip leading "report ID" byte */
666 			if (sc->report_id) {
667 				len--;
668 				buf++;
669 			}
670 
671 			wmt_process_report(sc, buf, len);
672 		} else {
673 tr_ignore:
674 			DPRINTF("Ignored transfer, %d bytes\n", len);
675 		}
676 
677 	case USB_ST_SETUP:
678 tr_setup:
679 		usbd_xfer_set_frame_len(xfer, 0, sc->isize);
680 		usbd_transfer_submit(xfer);
681 		break;
682 	default:
683 		if (error != USB_ERR_CANCELLED) {
684 			/* Try clear stall first */
685 			usbd_xfer_set_stall(xfer);
686 			goto tr_setup;
687 		}
688 		break;
689 	}
690 }
691 
692 static void
693 wmt_ev_close_11(struct evdev_dev *evdev, void *ev_softc)
694 {
695 	struct wmt_softc *sc = ev_softc;
696 
697 	mtx_assert(&sc->mtx, MA_OWNED);
698 	usbd_transfer_stop(sc->xfer[WMT_INTR_DT]);
699 }
700 
701 static int
702 wmt_ev_open_11(struct evdev_dev *evdev, void *ev_softc)
703 {
704 	struct wmt_softc *sc = ev_softc;
705 
706 	mtx_assert(&sc->mtx, MA_OWNED);
707 	usbd_transfer_start(sc->xfer[WMT_INTR_DT]);
708 
709 	return (0);
710 }
711 
712 static int
713 wmt_ev_close(struct evdev_dev *evdev)
714 {
715 	struct wmt_softc *sc = evdev_get_softc(evdev);
716 
717 	wmt_ev_close_11(evdev, sc);
718 
719 	return (0);
720 }
721 
722 static int
723 wmt_ev_open(struct evdev_dev *evdev)
724 {
725 	struct wmt_softc *sc = evdev_get_softc(evdev);
726 
727 	return (wmt_ev_open_11(evdev, sc));
728 
729 }
730 
731 static enum wmt_type
732 wmt_hid_parse(struct wmt_softc *sc, const void *d_ptr, uint16_t d_len)
733 {
734 	struct hid_item hi;
735 	struct hid_data *hd;
736 	size_t i;
737 	size_t cont = 0;
738 	enum wmt_type type = WMT_TYPE_UNSUPPORTED;
739 	uint32_t left_btn, btn;
740 	int32_t cont_count_max = 0;
741 	uint8_t report_id = 0;
742 	bool touch_coll = false;
743 	bool finger_coll = false;
744 	bool cont_count_found = false;
745 	bool scan_time_found = false;
746 	bool has_int_button = false;
747 
748 #define WMT_HI_ABSOLUTE(hi)	\
749 	(((hi).flags & (HIO_CONST|HIO_VARIABLE|HIO_RELATIVE)) == HIO_VARIABLE)
750 #define	HUMS_THQA_CERT	0xC5
751 
752 	/* Parse features for maximum contact count */
753 	hd = hid_start_parse(d_ptr, d_len, 1 << hid_feature);
754 	while (hid_get_item(hd, &hi)) {
755 		switch (hi.kind) {
756 		case hid_collection:
757 			if (hi.collevel == 1 && hi.usage ==
758 			    HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN)) {
759 				touch_coll = true;
760 				type = WMT_TYPE_TOUCHSCREEN;
761 				left_btn = 1;
762 				break;
763 			}
764 			if (hi.collevel == 1 && hi.usage ==
765 			    HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHPAD)) {
766 				touch_coll = true;
767 				type = WMT_TYPE_TOUCHPAD;
768 				left_btn = 2;
769 			}
770 			break;
771 		case hid_endcollection:
772 			if (hi.collevel == 0 && touch_coll)
773 				touch_coll = false;
774 			break;
775 		case hid_feature:
776 			if (hi.collevel == 1 && touch_coll && hi.usage ==
777 			      HID_USAGE2(HUP_MICROSOFT, HUMS_THQA_CERT)) {
778 				sc->thqa_cert_rid = hi.report_ID;
779 				break;
780 			}
781 			if (hi.collevel == 1 && touch_coll && hi.usage ==
782 			    HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX)) {
783 				cont_count_max = hi.logical_maximum;
784 				sc->cont_max_rid = hi.report_ID;
785 				sc->cont_max_loc = hi.loc;
786 				break;
787 			}
788 			if (hi.collevel == 1 && touch_coll && hi.usage ==
789 			    HID_USAGE2(HUP_DIGITIZERS, HUD_BUTTON_TYPE)) {
790 				sc->btn_type_rid = hi.report_ID;
791 				sc->btn_type_loc = hi.loc;
792 			}
793 			break;
794 		default:
795 			break;
796 		}
797 	}
798 	hid_end_parse(hd);
799 
800 	if (type == WMT_TYPE_UNSUPPORTED)
801 		return (WMT_TYPE_UNSUPPORTED);
802 	/* Maximum contact count is required usage */
803 	if (sc->cont_max_rid == 0)
804 		return (WMT_TYPE_UNSUPPORTED);
805 
806 	touch_coll = false;
807 
808 	/* Parse input for other parameters */
809 	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
810 	while (hid_get_item(hd, &hi)) {
811 		switch (hi.kind) {
812 		case hid_collection:
813 			if (hi.collevel == 1 && hi.usage ==
814 			    HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))
815 				touch_coll = true;
816 			else if (touch_coll && hi.collevel == 2 &&
817 			    (report_id == 0 || report_id == hi.report_ID) &&
818 			    hi.usage == HID_USAGE2(HUP_DIGITIZERS, HUD_FINGER))
819 				finger_coll = true;
820 			break;
821 		case hid_endcollection:
822 			if (hi.collevel == 1 && finger_coll) {
823 				finger_coll = false;
824 				cont++;
825 			} else if (hi.collevel == 0 && touch_coll)
826 				touch_coll = false;
827 			break;
828 		case hid_input:
829 			/*
830 			 * Ensure that all usages are located within the same
831 			 * report and proper collection.
832 			 */
833 			if (WMT_HI_ABSOLUTE(hi) && touch_coll &&
834 			    (report_id == 0 || report_id == hi.report_ID))
835 				report_id = hi.report_ID;
836 			else
837 				break;
838 
839 			if (hi.collevel == 1 && left_btn == 2 &&
840 			    hi.usage == HID_USAGE2(HUP_BUTTON, 1)) {
841 				has_int_button = true;
842 				sc->int_btn_loc = hi.loc;
843 				break;
844 			}
845 			if (hi.collevel == 1 &&
846 			    hi.usage >= HID_USAGE2(HUP_BUTTON, left_btn) &&
847 			    hi.usage <= HID_USAGE2(HUP_BUTTON, WMT_BTN_MAX)) {
848 				btn = (hi.usage & 0xFFFF) - left_btn;
849 				setbit(sc->buttons, btn);
850 				sc->btn_loc[btn] = hi.loc;
851 				if (btn >= sc->max_button)
852 					sc->max_button = btn + 1;
853 				break;
854 			}
855 			if (hi.collevel == 1 && hi.usage ==
856 			    HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTCOUNT)) {
857 				cont_count_found = true;
858 				sc->cont_count_loc = hi.loc;
859 				break;
860 			}
861 			/* Scan time is required but clobbered by evdev */
862 			if (hi.collevel == 1 && hi.usage ==
863 			    HID_USAGE2(HUP_DIGITIZERS, HUD_SCAN_TIME)) {
864 				scan_time_found = true;
865 				sc->scan_time_loc = hi.loc;
866 				sc->scan_time_max = hi.logical_maximum;
867 				break;
868 			}
869 
870 			if (!finger_coll || hi.collevel != 2)
871 				break;
872 			if (cont >= MAX_MT_SLOTS) {
873 				DPRINTF("Finger %zu ignored\n", cont);
874 				break;
875 			}
876 
877 			for (i = 0; i < WMT_N_USAGES; i++) {
878 				if (hi.usage == wmt_hid_map[i].usage) {
879 					/*
880 					 * HUG_X usage is an array mapped to
881 					 * both ABS_MT_POSITION and ABS_MT_TOOL
882 					 * events. So don`t stop search if we
883 					 * already have HUG_X mapping done.
884 					 */
885 					if (sc->locs[cont][i].size)
886 						continue;
887 					sc->locs[cont][i] = hi.loc;
888 					/*
889 					 * Hid parser returns valid logical and
890 					 * physical sizes for first finger only
891 					 * at least on ElanTS 0x04f3:0x0012.
892 					 */
893 					if (cont > 0)
894 						break;
895 					setbit(sc->caps, i);
896 					sc->ai[i] = (struct wmt_absinfo) {
897 					    .max = hi.logical_maximum,
898 					    .min = hi.logical_minimum,
899 					    .res = hid_item_resolution(&hi),
900 					};
901 					break;
902 				}
903 			}
904 			break;
905 		default:
906 			break;
907 		}
908 	}
909 	hid_end_parse(hd);
910 
911 	/* Check for required HID Usages */
912 	if (!cont_count_found || !scan_time_found || cont == 0)
913 		return (WMT_TYPE_UNSUPPORTED);
914 	for (i = 0; i < WMT_N_USAGES; i++) {
915 		if (wmt_hid_map[i].required && isclr(sc->caps, i))
916 			return (WMT_TYPE_UNSUPPORTED);
917 	}
918 
919 	/* Touchpads must have at least one button */
920 	if (type == WMT_TYPE_TOUCHPAD && !sc->max_button && !has_int_button)
921 		return (WMT_TYPE_UNSUPPORTED);
922 
923 	/*
924 	 * According to specifications 'Contact Count Maximum' should be read
925 	 * from Feature Report rather than from HID descriptor. Set sane
926 	 * default value now to handle the case of 'Get Report' request failure
927 	 */
928 	if (cont_count_max < 1)
929 		cont_count_max = cont;
930 
931 	/* Report touch orientation if both width and height are supported */
932 	if (isset(sc->caps, WMT_WIDTH) && isset(sc->caps, WMT_HEIGHT)) {
933 		setbit(sc->caps, WMT_ORIENTATION);
934 		sc->ai[WMT_ORIENTATION].max = 1;
935 	}
936 
937 	sc->isize = hid_report_size_max(d_ptr, d_len, hid_input, NULL);
938 	sc->report_len = hid_report_size(d_ptr, d_len, hid_input,
939 	    report_id);
940 	sc->cont_max_rlen = hid_report_size(d_ptr, d_len, hid_feature,
941 	    sc->cont_max_rid);
942 	if (sc->btn_type_rid > 0)
943 		sc->btn_type_rlen = hid_report_size(d_ptr, d_len,
944 		    hid_feature, sc->btn_type_rid);
945 	if (sc->thqa_cert_rid > 0)
946 		sc->thqa_cert_rlen = hid_report_size(d_ptr, d_len,
947 		    hid_feature, sc->thqa_cert_rid);
948 
949 	sc->report_id = report_id;
950 	sc->nconts_per_report = cont;
951 	sc->has_int_button = has_int_button;
952 	sc->cont_count_max = cont_count_max;
953 
954 	return (type);
955 }
956 
957 static int
958 wmt_set_input_mode(struct wmt_softc *sc, enum wmt_input_mode mode)
959 {
960 	struct usb_attach_arg *uaa = device_get_ivars(sc->dev);
961 	int err;
962 
963 	if (sc->input_mode_rlen < 3 || sc->input_mode_rlen > WMT_BSIZE) {
964 		DPRINTF("Feature report %hhu size invalid or too large: %u\n",
965 		    sc->input_mode_rid, sc->input_mode_rlen);
966 		return (USB_ERR_BAD_BUFSIZE);
967 	}
968 
969 	/* Input Mode report is not strictly required to be readable */
970 	err = usbd_req_get_report(uaa->device, NULL, sc->buf,
971 	    sc->input_mode_rlen, uaa->info.bIfaceIndex,
972 	    UHID_FEATURE_REPORT, sc->input_mode_rid);
973 	if (err != USB_ERR_NORMAL_COMPLETION)
974 		bzero(sc->buf + 1, sc->input_mode_rlen - 1);
975 
976 	sc->buf[0] = sc->input_mode_rid;
977 	hid_put_udata(sc->buf + 1, sc->input_mode_rlen - 1,
978 	    &sc->input_mode_loc, mode);
979 	err = usbd_req_set_report(uaa->device, NULL, sc->buf,
980 	    sc->input_mode_rlen, uaa->info.bIfaceIndex,
981 	    UHID_FEATURE_REPORT, sc->input_mode_rid);
982 
983 	return (err);
984 }
985 
986 static const STRUCT_USB_HOST_ID wmt_devs[] = {
987 	/* generic HID class w/o boot interface */
988 	{USB_IFACE_CLASS(UICLASS_HID),
989 	 USB_IFACE_SUBCLASS(0),},
990 };
991 
992 static device_method_t wmt_methods[] = {
993 	DEVMETHOD(device_probe, wmt_probe),
994 	DEVMETHOD(device_attach, wmt_attach),
995 	DEVMETHOD(device_detach, wmt_detach),
996 
997 	DEVMETHOD_END
998 };
999 
1000 static driver_t wmt_driver = {
1001 	.name = "wmt",
1002 	.methods = wmt_methods,
1003 	.size = sizeof(struct wmt_softc),
1004 };
1005 
1006 DRIVER_MODULE(wmt, uhub, wmt_driver, NULL, NULL);
1007 MODULE_DEPEND(wmt, usb, 1, 1, 1);
1008 MODULE_DEPEND(wmt, hid, 1, 1, 1);
1009 MODULE_DEPEND(wmt, evdev, 1, 1, 1);
1010 MODULE_VERSION(wmt, 1);
1011 USB_PNP_HOST_INFO(wmt_devs);
1012