]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/input/wmt.c
usb: clean up empty lines in .c and .h files
[FreeBSD/FreeBSD.git] / sys / dev / usb / input / wmt.c
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 "usbdevs.h"
49 #include <dev/usb/usb.h>
50 #include <dev/usb/usbdi.h>
51 #include <dev/usb/usbdi_util.h>
52 #include <dev/usb/usbhid.h>
53
54 #include <dev/usb/quirk/usb_quirk.h>
55
56 #include <dev/evdev/evdev.h>
57 #include <dev/evdev/input.h>
58
59 #define USB_DEBUG_VAR wmt_debug
60 #include <dev/usb/usb_debug.h>
61
62 #ifdef USB_DEBUG
63 static int wmt_debug = 0;
64
65 static SYSCTL_NODE(_hw_usb, OID_AUTO, wmt, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
66     "USB MSWindows 7/8/10 compatible Multi-touch Device");
67 SYSCTL_INT(_hw_usb_wmt, OID_AUTO, debug, CTLFLAG_RWTUN,
68     &wmt_debug, 1, "Debug level");
69 #endif
70
71 #define WMT_BSIZE       1024    /* bytes, buffer size */
72
73 enum {
74         WMT_INTR_DT,
75         WMT_N_TRANSFER,
76 };
77
78 enum {
79         WMT_TIP_SWITCH,
80 #define WMT_SLOT        WMT_TIP_SWITCH
81         WMT_WIDTH,
82 #define WMT_MAJOR       WMT_WIDTH
83         WMT_HEIGHT,
84 #define WMT_MINOR       WMT_HEIGHT
85         WMT_ORIENTATION,
86         WMT_X,
87         WMT_Y,
88         WMT_CONTACTID,
89         WMT_PRESSURE,
90         WMT_IN_RANGE,
91         WMT_CONFIDENCE,
92         WMT_TOOL_X,
93         WMT_TOOL_Y,
94         WMT_N_USAGES,
95 };
96
97 #define WMT_NO_CODE     (ABS_MAX + 10)
98 #define WMT_NO_USAGE    -1
99
100 struct wmt_hid_map_item {
101         char            name[5];
102         int32_t         usage;          /* HID usage */
103         uint32_t        code;           /* Evdev event code */
104         bool            required;       /* Required for MT Digitizers */
105 };
106
107 static const struct wmt_hid_map_item wmt_hid_map[WMT_N_USAGES] = {
108         [WMT_TIP_SWITCH] = {    /* WMT_SLOT */
109                 .name = "TIP",
110                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_SWITCH),
111                 .code = ABS_MT_SLOT,
112                 .required = true,
113         },
114         [WMT_WIDTH] = {         /* WMT_MAJOR */
115                 .name = "WDTH",
116                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_WIDTH),
117                 .code = ABS_MT_TOUCH_MAJOR,
118                 .required = false,
119         },
120         [WMT_HEIGHT] = {        /* WMT_MINOR */
121                 .name = "HGHT",
122                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_HEIGHT),
123                 .code = ABS_MT_TOUCH_MINOR,
124                 .required = false,
125         },
126         [WMT_ORIENTATION] = {
127                 .name = "ORIE",
128                 .usage = WMT_NO_USAGE,
129                 .code = ABS_MT_ORIENTATION,
130                 .required = false,
131         },
132         [WMT_X] = {
133                 .name = "X",
134                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
135                 .code = ABS_MT_POSITION_X,
136                 .required = true,
137         },
138         [WMT_Y] = {
139                 .name = "Y",
140                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
141                 .code = ABS_MT_POSITION_Y,
142                 .required = true,
143         },
144         [WMT_CONTACTID] = {
145                 .name = "C_ID",
146                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTID),
147                 .code = ABS_MT_TRACKING_ID,
148                 .required = true,
149         },
150         [WMT_PRESSURE] = {
151                 .name = "PRES",
152                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_TIP_PRESSURE),
153                 .code = ABS_MT_PRESSURE,
154                 .required = false,
155         },
156         [WMT_IN_RANGE] = {
157                 .name = "RANG",
158                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_IN_RANGE),
159                 .code = ABS_MT_DISTANCE,
160                 .required = false,
161         },
162         [WMT_CONFIDENCE] = {
163                 .name = "CONF",
164                 .usage = HID_USAGE2(HUP_DIGITIZERS, HUD_CONFIDENCE),
165                 .code = WMT_NO_CODE,
166                 .required = false,
167         },
168         [WMT_TOOL_X] = {        /* Shares HID usage with WMT_X */
169                 .name = "TL_X",
170                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
171                 .code = ABS_MT_TOOL_X,
172                 .required = false,
173         },
174         [WMT_TOOL_Y] = {        /* Shares HID usage with WMT_Y */
175                 .name = "TL_Y",
176                 .usage = HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
177                 .code = ABS_MT_TOOL_Y,
178                 .required = false,
179         },
180 };
181
182 struct wmt_absinfo {
183         int32_t                 min;
184         int32_t                 max;
185         int32_t                 res;
186 };
187
188 struct wmt_softc
189 {
190         device_t                dev;
191         struct mtx              mtx;
192         struct wmt_absinfo      ai[WMT_N_USAGES];
193         struct hid_location     locs[MAX_MT_SLOTS][WMT_N_USAGES];
194         struct hid_location     nconts_loc;
195
196         struct usb_xfer         *xfer[WMT_N_TRANSFER];
197         struct evdev_dev        *evdev;
198
199         uint32_t                slot_data[WMT_N_USAGES];
200         uint32_t                caps;
201         uint32_t                isize;
202         uint32_t                nconts_max;
203         uint32_t                report_len;
204         uint8_t                 report_id;
205
206         struct hid_location     cont_max_loc;
207         uint32_t                cont_max_rlen;
208         uint8_t                 cont_max_rid;
209         uint32_t                thqa_cert_rlen;
210         uint8_t                 thqa_cert_rid;
211
212         uint8_t                 buf[WMT_BSIZE] __aligned(4);
213 };
214
215 #define USAGE_SUPPORTED(caps, usage)    ((caps) & (1 << (usage)))
216 #define WMT_FOREACH_USAGE(caps, usage)                  \
217         for ((usage) = 0; (usage) < WMT_N_USAGES; ++(usage))    \
218                 if (USAGE_SUPPORTED((caps), (usage)))
219
220 static bool wmt_hid_parse(struct wmt_softc *, const void *, uint16_t);
221 static void wmt_cont_max_parse(struct wmt_softc *, const void *, uint16_t);
222
223 static usb_callback_t   wmt_intr_callback;
224
225 static device_probe_t   wmt_probe;
226 static device_attach_t  wmt_attach;
227 static device_detach_t  wmt_detach;
228
229 #if __FreeBSD_version >= 1200077
230 static evdev_open_t     wmt_ev_open;
231 static evdev_close_t    wmt_ev_close;
232 #else
233 static evdev_open_t     wmt_ev_open_11;
234 static evdev_close_t    wmt_ev_close_11;
235 #endif
236
237 static const struct evdev_methods wmt_evdev_methods = {
238 #if __FreeBSD_version >= 1200077
239         .ev_open = &wmt_ev_open,
240         .ev_close = &wmt_ev_close,
241 #else
242         .ev_open = &wmt_ev_open_11,
243         .ev_close = &wmt_ev_close_11,
244 #endif
245 };
246
247 static const struct usb_config wmt_config[WMT_N_TRANSFER] = {
248         [WMT_INTR_DT] = {
249                 .type = UE_INTERRUPT,
250                 .endpoint = UE_ADDR_ANY,
251                 .direction = UE_DIR_IN,
252                 .flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
253                 .bufsize = WMT_BSIZE,
254                 .callback = &wmt_intr_callback,
255         },
256 };
257
258 static int
259 wmt_probe(device_t dev)
260 {
261         struct usb_attach_arg *uaa = device_get_ivars(dev);
262         void *d_ptr;
263         uint16_t d_len;
264         int err;
265
266         if (uaa->usb_mode != USB_MODE_HOST)
267                 return (ENXIO);
268
269         if (uaa->info.bInterfaceClass != UICLASS_HID)
270                 return (ENXIO);
271
272         if (usb_test_quirk(uaa, UQ_WMT_IGNORE))
273                 return (ENXIO);
274
275         err = usbd_req_get_hid_desc(uaa->device, NULL,
276             &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
277         if (err)
278                 return (ENXIO);
279
280         if (wmt_hid_parse(NULL, d_ptr, d_len))
281                 err = BUS_PROBE_DEFAULT;
282         else
283                 err = ENXIO;
284
285         free(d_ptr, M_TEMP);
286         return (err);
287 }
288
289 static int
290 wmt_attach(device_t dev)
291 {
292         struct usb_attach_arg *uaa = device_get_ivars(dev);
293         struct wmt_softc *sc = device_get_softc(dev);
294         void *d_ptr;
295         uint16_t d_len;
296         size_t i;
297         int err;
298         bool hid_ok;
299
300         device_set_usb_desc(dev);
301         sc->dev = dev;
302
303         /* Get HID descriptor */
304         err = usbd_req_get_hid_desc(uaa->device, NULL,
305             &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
306         if (err) {
307                 DPRINTF("usbd_req_get_hid_desc error=%s\n", usbd_errstr(err));
308                 return (ENXIO);
309         }
310
311         hid_ok = wmt_hid_parse(sc, d_ptr, d_len);
312         free(d_ptr, M_TEMP);
313         if (!hid_ok) {
314                 DPRINTF("multi-touch HID descriptor not found\n");
315                 return (ENXIO);
316         }
317
318         /* Check HID report length */
319         if (sc->isize <= 0 || sc->isize > WMT_BSIZE) {
320                 DPRINTF("Input size invalid or too large: %d\n", sc->isize);
321                 return (ENXIO);
322         }
323
324         /* Fetch and parse "Contact count maximum" feature report */
325         if (sc->cont_max_rlen > 0 && sc->cont_max_rlen <= WMT_BSIZE) {
326                 err = usbd_req_get_report(uaa->device, NULL, sc->buf,
327                     sc->cont_max_rlen, uaa->info.bIfaceIndex,
328                     UHID_FEATURE_REPORT, sc->cont_max_rid);
329                 if (err == USB_ERR_NORMAL_COMPLETION)
330                         wmt_cont_max_parse(sc, sc->buf, sc->cont_max_rlen);
331                 else
332                         DPRINTF("usbd_req_get_report error=(%s)\n",
333                             usbd_errstr(err));
334         } else
335                 DPRINTF("Feature report %hhu size invalid or too large: %u\n",
336                     sc->cont_max_rid, sc->cont_max_rlen);
337
338         /* Fetch THQA certificate to enable some devices like WaveShare */
339         if (sc->thqa_cert_rlen > 0 && sc->thqa_cert_rlen <= WMT_BSIZE &&
340             sc->thqa_cert_rid != sc->cont_max_rid)
341                 (void)usbd_req_get_report(uaa->device, NULL, sc->buf,
342                     sc->thqa_cert_rlen, uaa->info.bIfaceIndex,
343                     UHID_FEATURE_REPORT, sc->thqa_cert_rid);
344
345         mtx_init(&sc->mtx, "wmt lock", NULL, MTX_DEF);
346
347         err = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
348             sc->xfer, wmt_config, WMT_N_TRANSFER, sc, &sc->mtx);
349         if (err != USB_ERR_NORMAL_COMPLETION) {
350                 DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err));
351                 goto detach;
352         }
353
354         sc->evdev = evdev_alloc();
355         evdev_set_name(sc->evdev, device_get_desc(dev));
356         evdev_set_phys(sc->evdev, device_get_nameunit(dev));
357         evdev_set_id(sc->evdev, BUS_USB, uaa->info.idVendor,
358             uaa->info.idProduct, 0);
359         evdev_set_serial(sc->evdev, usb_get_serial(uaa->device));
360         evdev_set_methods(sc->evdev, sc, &wmt_evdev_methods);
361         evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT);
362         evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT);
363         evdev_support_event(sc->evdev, EV_SYN);
364         evdev_support_event(sc->evdev, EV_ABS);
365         WMT_FOREACH_USAGE(sc->caps, i) {
366                 if (wmt_hid_map[i].code != WMT_NO_CODE)
367                         evdev_support_abs(sc->evdev, wmt_hid_map[i].code, 0,
368                             sc->ai[i].min, sc->ai[i].max, 0, 0, sc->ai[i].res);
369         }
370
371         err = evdev_register_mtx(sc->evdev, &sc->mtx);
372         if (err)
373                 goto detach;
374
375         return (0);
376
377 detach:
378         wmt_detach(dev);
379         return (ENXIO);
380 }
381
382 static int
383 wmt_detach(device_t dev)
384 {
385         struct wmt_softc *sc = device_get_softc(dev);
386
387         evdev_free(sc->evdev);
388         usbd_transfer_unsetup(sc->xfer, WMT_N_TRANSFER);
389         mtx_destroy(&sc->mtx);
390         return (0);
391 }
392
393 static void
394 wmt_process_report(struct wmt_softc *sc, uint8_t *buf, int len)
395 {
396         size_t usage;
397         uint32_t *slot_data = sc->slot_data;
398         uint32_t cont;
399         uint32_t nconts;
400         uint32_t width;
401         uint32_t height;
402         int32_t slot;
403
404         nconts = hid_get_data_unsigned(buf, len, &sc->nconts_loc);
405
406 #ifdef USB_DEBUG
407         DPRINTFN(6, "nconts = %u   ", (unsigned)nconts);
408         if (wmt_debug >= 6) {
409                 WMT_FOREACH_USAGE(sc->caps, usage) {
410                         if (wmt_hid_map[usage].usage != WMT_NO_USAGE)
411                                 printf(" %-4s", wmt_hid_map[usage].name);
412                 }
413                 printf("\n");
414         }
415 #endif
416
417         if (nconts > sc->nconts_max) {
418                 DPRINTF("Contact count overflow %u\n", (unsigned)nconts);
419                 nconts = sc->nconts_max;
420         }
421
422         /* Use protocol Type B for reporting events */
423         for (cont = 0; cont < nconts; cont++) {
424                 bzero(slot_data, sizeof(sc->slot_data));
425                 WMT_FOREACH_USAGE(sc->caps, usage) {
426                         if (sc->locs[cont][usage].size > 0)
427                                 slot_data[usage] = hid_get_data_unsigned(
428                                     buf, len, &sc->locs[cont][usage]);
429                 }
430
431                 slot = evdev_get_mt_slot_by_tracking_id(sc->evdev,
432                     slot_data[WMT_CONTACTID]);
433
434 #ifdef USB_DEBUG
435                 DPRINTFN(6, "cont%01x: data = ", cont);
436                 if (wmt_debug >= 6) {
437                         WMT_FOREACH_USAGE(sc->caps, usage) {
438                                 if (wmt_hid_map[usage].usage != WMT_NO_USAGE)
439                                         printf("%04x ", slot_data[usage]);
440                         }
441                         printf("slot = %d\n", (int)slot);
442                 }
443 #endif
444
445                 if (slot == -1) {
446                         DPRINTF("Slot overflow for contact_id %u\n",
447                             (unsigned)slot_data[WMT_CONTACTID]);
448                         continue;
449                 }
450
451                 if (slot_data[WMT_TIP_SWITCH] != 0 &&
452                     !(USAGE_SUPPORTED(sc->caps, WMT_CONFIDENCE) &&
453                       slot_data[WMT_CONFIDENCE] == 0)) {
454                         /* This finger is in proximity of the sensor */
455                         slot_data[WMT_SLOT] = slot;
456                         slot_data[WMT_IN_RANGE] = !slot_data[WMT_IN_RANGE];
457                         /* Divided by two to match visual scale of touch */
458                         width = slot_data[WMT_WIDTH] >> 1;
459                         height = slot_data[WMT_HEIGHT] >> 1;
460                         slot_data[WMT_ORIENTATION] = width > height;
461                         slot_data[WMT_MAJOR] = MAX(width, height);
462                         slot_data[WMT_MINOR] = MIN(width, height);
463
464                         WMT_FOREACH_USAGE(sc->caps, usage)
465                                 if (wmt_hid_map[usage].code != WMT_NO_CODE)
466                                         evdev_push_abs(sc->evdev,
467                                             wmt_hid_map[usage].code,
468                                             slot_data[usage]);
469                 } else {
470                         evdev_push_abs(sc->evdev, ABS_MT_SLOT, slot);
471                         evdev_push_abs(sc->evdev, ABS_MT_TRACKING_ID, -1);
472                 }
473         }
474         evdev_sync(sc->evdev);
475 }
476
477 static void
478 wmt_intr_callback(struct usb_xfer *xfer, usb_error_t error)
479 {
480         struct wmt_softc *sc = usbd_xfer_softc(xfer);
481         struct usb_page_cache *pc;
482         uint8_t *buf = sc->buf;
483         int len;
484
485         usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
486
487         switch (USB_GET_STATE(xfer)) {
488         case USB_ST_TRANSFERRED:
489                 pc = usbd_xfer_get_frame(xfer, 0);
490
491                 DPRINTFN(6, "sc=%p actlen=%d\n", sc, len);
492
493                 if (len >= (int)sc->report_len ||
494                     (len > 0 && sc->report_id != 0)) {
495                         /* Limit report length to the maximum */
496                         if (len > (int)sc->report_len)
497                                 len = sc->report_len;
498
499                         usbd_copy_out(pc, 0, buf, len);
500
501                         /* Ignore irrelevant reports */
502                         if (sc->report_id && *buf != sc->report_id)
503                                 goto tr_ignore;
504
505                         /* Make sure we don't process old data */
506                         if (len < sc->report_len)
507                                 bzero(buf + len, sc->report_len - len);
508
509                         /* Strip leading "report ID" byte */
510                         if (sc->report_id) {
511                                 len--;
512                                 buf++;
513                         }
514
515                         wmt_process_report(sc, buf, len);
516                 } else {
517 tr_ignore:
518                         DPRINTF("Ignored transfer, %d bytes\n", len);
519                 }
520
521         case USB_ST_SETUP:
522 tr_setup:
523                 usbd_xfer_set_frame_len(xfer, 0, sc->isize);
524                 usbd_transfer_submit(xfer);
525                 break;
526         default:
527                 if (error != USB_ERR_CANCELLED) {
528                         /* Try clear stall first */
529                         usbd_xfer_set_stall(xfer);
530                         goto tr_setup;
531                 }
532                 break;
533         }
534 }
535
536 static void
537 wmt_ev_close_11(struct evdev_dev *evdev, void *ev_softc)
538 {
539         struct wmt_softc *sc = ev_softc;
540
541         mtx_assert(&sc->mtx, MA_OWNED);
542         usbd_transfer_stop(sc->xfer[WMT_INTR_DT]);
543 }
544
545 static int
546 wmt_ev_open_11(struct evdev_dev *evdev, void *ev_softc)
547 {
548         struct wmt_softc *sc = ev_softc;
549
550         mtx_assert(&sc->mtx, MA_OWNED);
551         usbd_transfer_start(sc->xfer[WMT_INTR_DT]);
552
553         return (0);
554 }
555
556 #if __FreeBSD_version >= 1200077
557 static int
558 wmt_ev_close(struct evdev_dev *evdev)
559 {
560         struct wmt_softc *sc = evdev_get_softc(evdev);
561
562         wmt_ev_close_11(evdev, sc);
563
564         return (0);
565 }
566
567 static int
568 wmt_ev_open(struct evdev_dev *evdev)
569 {
570         struct wmt_softc *sc = evdev_get_softc(evdev);
571
572         return (wmt_ev_open_11(evdev, sc));
573
574 }
575 #endif
576
577 /* port of userland hid_report_size() from usbhid(3) to kernel */
578 static int
579 wmt_hid_report_size(const void *buf, uint16_t len, enum hid_kind k, uint8_t id)
580 {
581         struct hid_data *d;
582         struct hid_item h;
583         uint32_t temp;
584         uint32_t hpos;
585         uint32_t lpos;
586         int report_id = 0;
587
588         hpos = 0;
589         lpos = 0xFFFFFFFF;
590
591         for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) {
592                 if (h.kind == k && h.report_ID == id) {
593                         /* compute minimum */
594                         if (lpos > h.loc.pos)
595                                 lpos = h.loc.pos;
596                         /* compute end position */
597                         temp = h.loc.pos + (h.loc.size * h.loc.count);
598                         /* compute maximum */
599                         if (hpos < temp)
600                                 hpos = temp;
601                         if (h.report_ID != 0)
602                                 report_id = 1;
603                 }
604         }
605         hid_end_parse(d);
606
607         /* safety check - can happen in case of currupt descriptors */
608         if (lpos > hpos)
609                 temp = 0;
610         else
611                 temp = hpos - lpos;
612
613         /* return length in bytes rounded up */
614         return ((temp + 7) / 8 + report_id);
615 }
616
617 static bool
618 wmt_hid_parse(struct wmt_softc *sc, const void *d_ptr, uint16_t d_len)
619 {
620         struct hid_item hi;
621         struct hid_data *hd;
622         size_t i;
623         size_t cont = 0;
624         uint32_t caps = 0;
625         int32_t cont_count_max = 0;
626         uint8_t report_id = 0;
627         uint8_t cont_max_rid = 0;
628         uint8_t thqa_cert_rid = 0;
629         bool touch_coll = false;
630         bool finger_coll = false;
631         bool cont_count_found = false;
632         bool scan_time_found = false;
633
634 #define WMT_HI_ABSOLUTE(hi)     \
635         (((hi).flags & (HIO_CONST|HIO_VARIABLE|HIO_RELATIVE)) == HIO_VARIABLE)
636 #define HUMS_THQA_CERT  0xC5
637
638         /* Parse features for maximum contact count */
639         hd = hid_start_parse(d_ptr, d_len, 1 << hid_feature);
640         while (hid_get_item(hd, &hi)) {
641                 switch (hi.kind) {
642                 case hid_collection:
643                         if (hi.collevel == 1 && hi.usage ==
644                             HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))
645                                 touch_coll = true;
646                         break;
647                 case hid_endcollection:
648                         if (hi.collevel == 0 && touch_coll)
649                                 touch_coll = false;
650                         break;
651                 case hid_feature:
652                         if (hi.collevel == 1 && touch_coll && hi.usage ==
653                               HID_USAGE2(HUP_MICROSOFT, HUMS_THQA_CERT)) {
654                                 thqa_cert_rid = hi.report_ID;
655                                 break;
656                         }
657                         if (hi.collevel == 1 && touch_coll && hi.usage ==
658                             HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACT_MAX)) {
659                                 cont_count_max = hi.logical_maximum;
660                                 cont_max_rid = hi.report_ID;
661                                 if (sc != NULL)
662                                         sc->cont_max_loc = hi.loc;
663                         }
664                         break;
665                 default:
666                         break;
667                 }
668         }
669         hid_end_parse(hd);
670
671         /* Maximum contact count is required usage */
672         if (cont_max_rid == 0)
673                 return (false);
674
675         touch_coll = false;
676
677         /* Parse input for other parameters */
678         hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
679         while (hid_get_item(hd, &hi)) {
680                 switch (hi.kind) {
681                 case hid_collection:
682                         if (hi.collevel == 1 && hi.usage ==
683                             HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN))
684                                 touch_coll = true;
685                         else if (touch_coll && hi.collevel == 2 &&
686                             (report_id == 0 || report_id == hi.report_ID) &&
687                             hi.usage == HID_USAGE2(HUP_DIGITIZERS, HUD_FINGER))
688                                 finger_coll = true;
689                         break;
690                 case hid_endcollection:
691                         if (hi.collevel == 1 && finger_coll) {
692                                 finger_coll = false;
693                                 cont++;
694                         } else if (hi.collevel == 0 && touch_coll)
695                                 touch_coll = false;
696                         break;
697                 case hid_input:
698                         /*
699                          * Ensure that all usages are located within the same
700                          * report and proper collection.
701                          */
702                         if (WMT_HI_ABSOLUTE(hi) && touch_coll &&
703                             (report_id == 0 || report_id == hi.report_ID))
704                                 report_id = hi.report_ID;
705                         else
706                                 break;
707
708                         if (hi.collevel == 1 && hi.usage ==
709                             HID_USAGE2(HUP_DIGITIZERS, HUD_CONTACTCOUNT)) {
710                                 cont_count_found = true;
711                                 if (sc != NULL)
712                                         sc->nconts_loc = hi.loc;
713                                 break;
714                         }
715                         /* Scan time is required but clobbered by evdev */
716                         if (hi.collevel == 1 && hi.usage ==
717                             HID_USAGE2(HUP_DIGITIZERS, HUD_SCAN_TIME)) {
718                                 scan_time_found = true;
719                                 break;
720                         }
721
722                         if (!finger_coll || hi.collevel != 2)
723                                 break;
724                         if (sc == NULL && cont > 0)
725                                 break;
726                         if (cont >= MAX_MT_SLOTS) {
727                                 DPRINTF("Finger %zu ignored\n", cont);
728                                 break;
729                         }
730
731                         for (i = 0; i < WMT_N_USAGES; i++) {
732                                 if (hi.usage == wmt_hid_map[i].usage) {
733                                         if (sc == NULL) {
734                                                 if (USAGE_SUPPORTED(caps, i))
735                                                         continue;
736                                                 caps |= 1 << i;
737                                                 break;
738                                         }
739                                         /*
740                                          * HUG_X usage is an array mapped to
741                                          * both ABS_MT_POSITION and ABS_MT_TOOL
742                                          * events. So don`t stop search if we
743                                          * already have HUG_X mapping done.
744                                          */
745                                         if (sc->locs[cont][i].size)
746                                                 continue;
747                                         sc->locs[cont][i] = hi.loc;
748                                         /*
749                                          * Hid parser returns valid logical and
750                                          * physical sizes for first finger only
751                                          * at least on ElanTS 0x04f3:0x0012.
752                                          */
753                                         if (cont > 0)
754                                                 break;
755                                         caps |= 1 << i;
756                                         sc->ai[i] = (struct wmt_absinfo) {
757                                             .max = hi.logical_maximum,
758                                             .min = hi.logical_minimum,
759                                             .res = hid_item_resolution(&hi),
760                                         };
761                                         break;
762                                 }
763                         }
764                         break;
765                 default:
766                         break;
767                 }
768         }
769         hid_end_parse(hd);
770
771         /* Check for required HID Usages */
772         if (!cont_count_found || !scan_time_found || cont == 0)
773                 return (false);
774         for (i = 0; i < WMT_N_USAGES; i++) {
775                 if (wmt_hid_map[i].required && !USAGE_SUPPORTED(caps, i))
776                         return (false);
777         }
778
779         /* Stop probing here */
780         if (sc == NULL)
781                 return (true);
782
783         /*
784          * According to specifications 'Contact Count Maximum' should be read
785          * from Feature Report rather than from HID descriptor. Set sane
786          * default value now to handle the case of 'Get Report' request failure
787          */
788         if (cont_count_max < 1)
789                 cont_count_max = cont;
790
791         /* Cap contact count maximum to MAX_MT_SLOTS */
792         if (cont_count_max > MAX_MT_SLOTS)
793                 cont_count_max = MAX_MT_SLOTS;
794
795         /* Set number of MT protocol type B slots */
796         sc->ai[WMT_SLOT] = (struct wmt_absinfo) {
797                 .min = 0,
798                 .max = cont_count_max - 1,
799                 .res = 0,
800         };
801
802         /* Report touch orientation if both width and height are supported */
803         if (USAGE_SUPPORTED(caps, WMT_WIDTH) &&
804             USAGE_SUPPORTED(caps, WMT_HEIGHT)) {
805                 caps |= (1 << WMT_ORIENTATION);
806                 sc->ai[WMT_ORIENTATION].max = 1;
807         }
808
809         sc->isize = hid_report_size(d_ptr, d_len, hid_input, NULL);
810         sc->report_len = wmt_hid_report_size(d_ptr, d_len, hid_input,
811             report_id);
812         sc->cont_max_rlen = wmt_hid_report_size(d_ptr, d_len, hid_feature,
813             cont_max_rid);
814         if (thqa_cert_rid > 0)
815                 sc->thqa_cert_rlen = wmt_hid_report_size(d_ptr, d_len,
816                     hid_feature, thqa_cert_rid);
817
818         sc->report_id = report_id;
819         sc->caps = caps;
820         sc->nconts_max = cont;
821         sc->cont_max_rid = cont_max_rid;
822         sc->thqa_cert_rid = thqa_cert_rid;
823
824         /* Announce information about the touch device */
825         device_printf(sc->dev,
826             "%d contacts and [%s%s%s%s%s]. Report range [%d:%d] - [%d:%d]\n",
827             (int)cont_count_max,
828             USAGE_SUPPORTED(sc->caps, WMT_IN_RANGE) ? "R" : "",
829             USAGE_SUPPORTED(sc->caps, WMT_CONFIDENCE) ? "C" : "",
830             USAGE_SUPPORTED(sc->caps, WMT_WIDTH) ? "W" : "",
831             USAGE_SUPPORTED(sc->caps, WMT_HEIGHT) ? "H" : "",
832             USAGE_SUPPORTED(sc->caps, WMT_PRESSURE) ? "P" : "",
833             (int)sc->ai[WMT_X].min, (int)sc->ai[WMT_Y].min,
834             (int)sc->ai[WMT_X].max, (int)sc->ai[WMT_Y].max);
835         return (true);
836 }
837
838 static void
839 wmt_cont_max_parse(struct wmt_softc *sc, const void *r_ptr, uint16_t r_len)
840 {
841         uint32_t cont_count_max;
842
843         cont_count_max = hid_get_data_unsigned((const uint8_t *)r_ptr + 1,
844             r_len - 1, &sc->cont_max_loc);
845         if (cont_count_max > MAX_MT_SLOTS) {
846                 DPRINTF("Hardware reported %d contacts while only %d is "
847                     "supported\n", (int)cont_count_max, MAX_MT_SLOTS);
848                 cont_count_max = MAX_MT_SLOTS;
849         }
850         /* Feature report is a primary source of 'Contact Count Maximum' */
851         if (cont_count_max > 0 &&
852             cont_count_max != sc->ai[WMT_SLOT].max + 1) {
853                 sc->ai[WMT_SLOT].max = cont_count_max - 1;
854                 device_printf(sc->dev, "%d feature report contacts",
855                     cont_count_max);
856         }
857 }
858
859 static const STRUCT_USB_HOST_ID wmt_devs[] = {
860         /* generic HID class w/o boot interface */
861         {USB_IFACE_CLASS(UICLASS_HID),
862          USB_IFACE_SUBCLASS(0),},
863 };
864
865 static devclass_t wmt_devclass;
866
867 static device_method_t wmt_methods[] = {
868         DEVMETHOD(device_probe, wmt_probe),
869         DEVMETHOD(device_attach, wmt_attach),
870         DEVMETHOD(device_detach, wmt_detach),
871
872         DEVMETHOD_END
873 };
874
875 static driver_t wmt_driver = {
876         .name = "wmt",
877         .methods = wmt_methods,
878         .size = sizeof(struct wmt_softc),
879 };
880
881 DRIVER_MODULE(wmt, uhub, wmt_driver, wmt_devclass, NULL, 0);
882 MODULE_DEPEND(wmt, usb, 1, 1, 1);
883 MODULE_DEPEND(wmt, evdev, 1, 1, 1);
884 MODULE_VERSION(wmt, 1);
885 USB_PNP_HOST_INFO(wmt_devs);