Lines Matching +full:multi +full:- +full:touch
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2014-2020 Vladimir Kondratyev <wulf@FreeBSD.org>
30 * MS Windows 7/8/10 compatible HID Multi-touch Device driver.
31 * https://msdn.microsoft.com/en-us/library/windows/hardware/jj151569(v=vs.85).aspx
32 …/download.microsoft.com/download/7/d/d/7dd44bb7-2a7a-4505-ac1c-7227d3d96d5b/hid-over-i2c-protocol-…
33 * https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
59 "MSWindows 7/8/10 compatible HID Multi-touch Device");
94 #define HMT_NO_USAGE -1
192 bool touch; member
282 if (sc->type == HMT_TYPE_UNKNOWN) in hmt_probe()
283 sc->type = hmt_hid_parse(sc, d_ptr, d_len, in hmt_probe()
285 if (sc->type == HMT_TYPE_UNSUPPORTED) in hmt_probe()
289 sc->type == HMT_TYPE_TOUCHPAD ? "TouchPad" : "TouchScreen"); in hmt_probe()
314 sc->dev = dev; in hmt_attach()
321 if (sc->cont_max_rlen > 1) { in hmt_attach()
322 err = hid_get_report(dev, fbuf, sc->cont_max_rlen, &rsize, in hmt_attach()
323 HID_FEATURE_REPORT, sc->cont_max_rid); in hmt_attach()
324 if (err == 0 && (rsize - 1) * 8 >= in hmt_attach()
325 sc->cont_max_loc.pos + sc->cont_max_loc.size) { in hmt_attach()
327 sc->cont_max_rlen - 1, &sc->cont_max_loc); in hmt_attach()
333 sc->cont_count_max = cont_count_max; in hmt_attach()
337 if (sc->cont_count_max == 0) in hmt_attach()
338 sc->cont_count_max = sc->type == HMT_TYPE_TOUCHSCREEN ? 10 : 5; in hmt_attach()
341 if (sc->btn_type_rlen > 1 && sc->btn_type_rid != sc->cont_max_rid) { in hmt_attach()
343 err = hid_get_report(dev, fbuf, sc->btn_type_rlen, &rsize, in hmt_attach()
344 HID_FEATURE_REPORT, sc->btn_type_rid); in hmt_attach()
348 if (sc->btn_type_rlen > 1 && err == 0 && (rsize - 1) * 8 >= in hmt_attach()
349 sc->btn_type_loc.pos + sc->btn_type_loc.size) in hmt_attach()
350 sc->is_clickpad = hid_get_udata(fbuf + 1, sc->btn_type_rlen - 1, in hmt_attach()
351 &sc->btn_type_loc) == 0; in hmt_attach()
353 sc->is_clickpad = sc->max_button == 0 && sc->has_int_button; in hmt_attach()
356 if (sc->thqa_cert_rlen > 1 && sc->thqa_cert_rid != sc->cont_max_rid) in hmt_attach()
357 (void)hid_get_report(dev, fbuf, sc->thqa_cert_rlen, NULL, in hmt_attach()
358 HID_FEATURE_REPORT, sc->thqa_cert_rid); in hmt_attach()
363 if (sc->type == HMT_TYPE_TOUCHPAD) { in hmt_attach()
370 if (sc->cont_count_max > MAX_MT_SLOTS) { in hmt_attach()
372 "supported\n", sc->cont_count_max, MAX_MT_SLOTS); in hmt_attach()
373 sc->cont_count_max = MAX_MT_SLOTS; in hmt_attach()
376 if (sc->has_scan_time && in hmt_attach()
378 sc->do_timestamps = true; in hmt_attach()
381 sc->iichid_sampling = true; in hmt_attach()
386 sc->evdev = evdev_alloc(); in hmt_attach()
387 evdev_set_name(sc->evdev, device_get_desc(dev)); in hmt_attach()
388 evdev_set_phys(sc->evdev, device_get_nameunit(dev)); in hmt_attach()
389 evdev_set_id(sc->evdev, hw->idBus, hw->idVendor, hw->idProduct, in hmt_attach()
390 hw->idVersion); in hmt_attach()
391 evdev_set_serial(sc->evdev, hw->serial); in hmt_attach()
392 evdev_set_methods(sc->evdev, dev, &hmt_evdev_methods); in hmt_attach()
393 evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_STCOMPAT); in hmt_attach()
394 evdev_set_flag(sc->evdev, EVDEV_FLAG_EXT_EPOCH); /* hidbus child */ in hmt_attach()
395 switch (sc->type) { in hmt_attach()
397 evdev_support_prop(sc->evdev, INPUT_PROP_DIRECT); in hmt_attach()
400 evdev_support_prop(sc->evdev, INPUT_PROP_POINTER); in hmt_attach()
401 if (sc->is_clickpad) in hmt_attach()
402 evdev_support_prop(sc->evdev, INPUT_PROP_BUTTONPAD); in hmt_attach()
405 KASSERT(0, ("hmt_attach: unsupported touch device type")); in hmt_attach()
407 evdev_support_event(sc->evdev, EV_SYN); in hmt_attach()
408 evdev_support_event(sc->evdev, EV_ABS); in hmt_attach()
409 if (sc->do_timestamps) { in hmt_attach()
410 evdev_support_event(sc->evdev, EV_MSC); in hmt_attach()
411 evdev_support_msc(sc->evdev, MSC_TIMESTAMP); in hmt_attach()
414 if (sc->iichid_sampling) in hmt_attach()
415 evdev_set_flag(sc->evdev, EVDEV_FLAG_MT_AUTOREL); in hmt_attach()
418 if (sc->max_button != 0 || sc->has_int_button) { in hmt_attach()
419 evdev_support_event(sc->evdev, EV_KEY); in hmt_attach()
420 if (sc->has_int_button) in hmt_attach()
421 evdev_support_key(sc->evdev, BTN_LEFT); in hmt_attach()
422 for (btn = 0; btn < sc->max_button; ++btn) { in hmt_attach()
423 if (isset(sc->buttons, btn)) { in hmt_attach()
424 evdev_support_key(sc->evdev, BTN_MOUSE + btn); in hmt_attach()
429 evdev_support_abs(sc->evdev, in hmt_attach()
430 ABS_MT_SLOT, 0, sc->cont_count_max - 1, 0, 0, 0); in hmt_attach()
431 HMT_FOREACH_USAGE(sc->caps, i) { in hmt_attach()
433 evdev_support_abs(sc->evdev, ABS_MT_FIRST + i, in hmt_attach()
434 sc->ai[i].min, sc->ai[i].max, 0, 0, sc->ai[i].res); in hmt_attach()
437 err = evdev_register(sc->evdev); in hmt_attach()
443 /* Announce information about the touch device */ in hmt_attach()
444 device_printf(sc->dev, "%s %s with %d external button%s%s\n", in hmt_attach()
445 sc->cont_count_max > 1 ? "Multitouch" : "Singletouch", in hmt_attach()
446 sc->type == HMT_TYPE_TOUCHSCREEN ? "touchscreen" : "touchpad", in hmt_attach()
448 sc->is_clickpad ? ", click-pad" : ""); in hmt_attach()
449 device_printf(sc->dev, in hmt_attach()
450 "%d contact%s with [%s%s%s%s%s] properties. Report range [%d:%d] - [%d:%d]\n", in hmt_attach()
451 (int)sc->cont_count_max, sc->cont_count_max != 1 ? "s" : "", in hmt_attach()
452 isset(sc->caps, HMT_IN_RANGE) ? "R" : "", in hmt_attach()
453 isset(sc->caps, HMT_CONFIDENCE) ? "C" : "", in hmt_attach()
454 isset(sc->caps, HMT_WIDTH) ? "W" : "", in hmt_attach()
455 isset(sc->caps, HMT_HEIGHT) ? "H" : "", in hmt_attach()
456 isset(sc->caps, HMT_PRESSURE) ? "P" : "", in hmt_attach()
457 (int)sc->ai[HMT_X].min, (int)sc->ai[HMT_Y].min, in hmt_attach()
458 (int)sc->ai[HMT_X].max, (int)sc->ai[HMT_Y].max); in hmt_attach()
468 evdev_free(sc->evdev); in hmt_detach()
494 * "stuck touch" problem caused by miss of finger release events. in hmt_intr()
497 if (sc->iichid_sampling && len == 0) { in hmt_intr()
498 sc->prev_touch = false; in hmt_intr()
499 sc->timestamp = 0; in hmt_intr()
501 evdev_sync(sc->evdev); in hmt_intr()
507 id = sc->report_id != 0 ? *(uint8_t *)buf : 0; in hmt_intr()
508 if (sc->report_id != id) { in hmt_intr()
514 if (sc->report_id != 0) { in hmt_intr()
515 len--; in hmt_intr()
528 * collection that is embedded in the top-level collection." in hmt_intr()
531 * report with contactid=0 but contactids are zero-based, find in hmt_intr()
534 if (sc->has_cont_count) in hmt_intr()
535 cont_count = hid_get_udata(buf, len, &sc->cont_count_loc); in hmt_intr()
542 * 4 concurrent physical contacts, can set up its top-level collection in hmt_intr()
553 sc->nconts_todo = cont_count; in hmt_intr()
558 HMT_FOREACH_USAGE(sc->caps, usage) { in hmt_intr()
560 printf(" %-4s", hmt_hid_map[usage].name); in hmt_intr()
567 cont_count = MIN(sc->nconts_todo, sc->nconts_per_report); in hmt_intr()
571 slot_data = &sc->slot_data; in hmt_intr()
572 bzero(slot_data, sizeof(sc->slot_data)); in hmt_intr()
573 HMT_FOREACH_USAGE(sc->caps, usage) { in hmt_intr()
574 if (sc->locs[cont][usage].size > 0) in hmt_intr()
575 slot_data->val[usage] = hid_get_udata( in hmt_intr()
576 buf, len, &sc->locs[cont][usage]); in hmt_intr()
579 slot = evdev_mt_id_to_slot(sc->evdev, slot_data->id); in hmt_intr()
584 HMT_FOREACH_USAGE(sc->caps, usage) { in hmt_intr()
586 printf("%04x ", slot_data->val[usage]); in hmt_intr()
592 if (slot == -1) { in hmt_intr()
594 (unsigned)slot_data->id); in hmt_intr()
598 if (slot_data->val[HMT_TIP_SWITCH] != 0 && in hmt_intr()
599 !(isset(sc->caps, HMT_CONFIDENCE) && in hmt_intr()
600 slot_data->val[HMT_CONFIDENCE] == 0)) { in hmt_intr()
602 sc->touch = true; in hmt_intr()
603 slot_data->dist = !slot_data->val[HMT_IN_RANGE]; in hmt_intr()
604 /* Divided by two to match visual scale of touch */ in hmt_intr()
605 width = slot_data->val[HMT_WIDTH] >> 1; in hmt_intr()
606 height = slot_data->val[HMT_HEIGHT] >> 1; in hmt_intr()
607 slot_data->ori = width > height; in hmt_intr()
608 slot_data->maj = MAX(width, height); in hmt_intr()
609 slot_data->min = MIN(width, height); in hmt_intr()
613 evdev_mt_push_slot(sc->evdev, slot, slot_data); in hmt_intr()
616 sc->nconts_todo -= cont_count; in hmt_intr()
617 if (sc->do_timestamps && sc->nconts_todo == 0) { in hmt_intr()
619 scan_time = hid_get_udata(buf, len, &sc->scan_time_loc); in hmt_intr()
620 if (sc->prev_touch) { in hmt_intr()
621 delta = scan_time - sc->scan_time; in hmt_intr()
623 delta += sc->scan_time_max; in hmt_intr()
626 sc->scan_time = scan_time; in hmt_intr()
627 sc->timestamp += delta * 100; in hmt_intr()
628 evdev_push_msc(sc->evdev, MSC_TIMESTAMP, sc->timestamp); in hmt_intr()
629 sc->prev_touch = sc->touch; in hmt_intr()
630 sc->touch = false; in hmt_intr()
631 if (!sc->prev_touch) in hmt_intr()
632 sc->timestamp = 0; in hmt_intr()
634 if (sc->nconts_todo == 0) { in hmt_intr()
636 if (sc->has_int_button) in hmt_intr()
637 int_btn = hid_get_data(buf, len, &sc->int_btn_loc); in hmt_intr()
638 if (isset(sc->buttons, 0)) in hmt_intr()
639 left_btn = hid_get_data(buf, len, &sc->btn_loc[0]); in hmt_intr()
640 if (sc->has_int_button || isset(sc->buttons, 0)) in hmt_intr()
641 evdev_push_key(sc->evdev, BTN_LEFT, in hmt_intr()
643 for (btn = 1; btn < sc->max_button; ++btn) { in hmt_intr()
644 if (isset(sc->buttons, btn)) in hmt_intr()
645 evdev_push_key(sc->evdev, BTN_MOUSE + btn, in hmt_intr()
648 &sc->btn_loc[btn]) != 0); in hmt_intr()
650 evdev_sync(sc->evdev); in hmt_intr()
680 * Button 1 - Indicates Button State for touchpad button integrated in hmt_hid_parse()
682 * Button 2 - Indicates Button State for external button for primary in hmt_hid_parse()
684 * Button 3 - Indicates Button State for external button for secondary in hmt_hid_parse()
705 tlc_index, 0, &sc->cont_max_loc, &flags, &sc->cont_max_rid, &ai) || in hmt_hid_parse()
714 tlc_index, 0, &sc->btn_type_loc, &flags, &sc->btn_type_rid, NULL) in hmt_hid_parse()
716 sc->btn_type_rid = 0; in hmt_hid_parse()
720 hid_feature, tlc_index, 0, NULL, NULL, &sc->thqa_cert_rid, NULL); in hmt_hid_parse()
750 sc->int_btn_loc = hi.loc; in hmt_hid_parse()
755 btn = (hi.usage & 0xFFFF) - left_btn; in hmt_hid_parse()
756 setbit(sc->buttons, btn); in hmt_hid_parse()
757 sc->btn_loc[btn] = hi.loc; in hmt_hid_parse()
758 if (btn >= sc->max_button) in hmt_hid_parse()
759 sc->max_button = btn + 1; in hmt_hid_parse()
765 sc->cont_count_loc = hi.loc; in hmt_hid_parse()
771 sc->scan_time_loc = hi.loc; in hmt_hid_parse()
772 sc->scan_time_max = hi.logical_maximum; in hmt_hid_parse()
791 if (sc->locs[cont][i].size) in hmt_hid_parse()
793 sc->locs[cont][i] = hi.loc; in hmt_hid_parse()
801 setbit(sc->caps, i); in hmt_hid_parse()
802 sc->ai[i] = (struct hid_absinfo) { in hmt_hid_parse()
821 if (hmt_hid_map[i].required && isclr(sc->caps, i)) in hmt_hid_parse()
826 if (type == HMT_TYPE_TOUCHPAD && !sc->max_button && !has_int_button) in hmt_hid_parse()
837 /* Report touch orientation if both width and height are supported */ in hmt_hid_parse()
838 if (isset(sc->caps, HMT_WIDTH) && isset(sc->caps, HMT_HEIGHT)) { in hmt_hid_parse()
839 setbit(sc->caps, HMT_ORIENTATION); in hmt_hid_parse()
840 sc->ai[HMT_ORIENTATION].max = 1; in hmt_hid_parse()
843 sc->cont_max_rlen = hid_report_size(d_ptr, d_len, hid_feature, in hmt_hid_parse()
844 sc->cont_max_rid); in hmt_hid_parse()
845 if (sc->btn_type_rid > 0) in hmt_hid_parse()
846 sc->btn_type_rlen = hid_report_size(d_ptr, d_len, in hmt_hid_parse()
847 hid_feature, sc->btn_type_rid); in hmt_hid_parse()
848 if (sc->thqa_cert_rid > 0) in hmt_hid_parse()
849 sc->thqa_cert_rlen = hid_report_size(d_ptr, d_len, in hmt_hid_parse()
850 hid_feature, sc->thqa_cert_rid); in hmt_hid_parse()
852 sc->report_id = report_id; in hmt_hid_parse()
853 sc->cont_count_max = cont_count_max; in hmt_hid_parse()
854 sc->nconts_per_report = cont; in hmt_hid_parse()
855 sc->has_int_button = has_int_button; in hmt_hid_parse()
856 sc->has_cont_count = cont_count_found; in hmt_hid_parse()
857 sc->has_scan_time = scan_time_found; in hmt_hid_parse()
872 hconf = hidbus_find_child(device_get_parent(sc->dev), in hmt_set_input_mode()