1 /*- 2 * Copyright (c) 2016, 2020 Vladimir Kondratyev <[email protected]> 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 * $FreeBSD$ 27 */ 28 /*- 29 * Copyright (c) 2015, 2016 Ulf Brosziewski 30 * 31 * Permission to use, copy, modify, and distribute this software for any 32 * purpose with or without fee is hereby granted, provided that the above 33 * copyright notice and this permission notice appear in all copies. 34 * 35 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 36 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 37 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 38 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 39 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 40 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 41 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/lock.h> 46 #include <sys/malloc.h> 47 #include <sys/mutex.h> 48 #include <sys/systm.h> 49 50 #include <dev/evdev/evdev.h> 51 #include <dev/evdev/evdev_private.h> 52 #include <dev/evdev/input.h> 53 54 #ifdef DEBUG 55 #define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args) 56 #else 57 #define debugf(fmt, args...) 58 #endif 59 60 typedef u_int slotset_t; 61 62 _Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big"); 63 64 #define FOREACHBIT(v, i) \ 65 for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1) 66 67 struct { 68 uint16_t mt; 69 uint16_t st; 70 int32_t max; 71 } static evdev_mtstmap[] = { 72 { ABS_MT_POSITION_X, ABS_X, 0 }, 73 { ABS_MT_POSITION_Y, ABS_Y, 0 }, 74 { ABS_MT_PRESSURE, ABS_PRESSURE, 255 }, 75 { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH, 15 }, 76 }; 77 78 struct evdev_mt { 79 int last_reported_slot; 80 uint16_t tracking_id; 81 int32_t tracking_ids[MAX_MT_SLOTS]; 82 u_int mtst_events; 83 /* the set of slots with active touches */ 84 slotset_t touches; 85 /* the set of slots with unsynchronized state */ 86 slotset_t frame; 87 /* the set of slots to match with active touches */ 88 slotset_t match_frame; 89 int match_slot; 90 union evdev_mt_slot *match_slots; 91 int *matrix; 92 union evdev_mt_slot slots[]; 93 }; 94 95 static void evdev_mt_send_st_compat(struct evdev_dev *); 96 static void evdev_mt_send_autorel(struct evdev_dev *); 97 static void evdev_mt_replay_events(struct evdev_dev *); 98 99 static inline int 100 ffc_slot(struct evdev_dev *evdev, slotset_t slots) 101 { 102 return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1); 103 } 104 105 void 106 evdev_mt_init(struct evdev_dev *evdev) 107 { 108 struct evdev_mt *mt; 109 size_t size = offsetof(struct evdev_mt, slots); 110 int slot, slots; 111 112 slots = MAXIMAL_MT_SLOT(evdev) + 1; 113 size += sizeof(mt->slots[0]) * slots; 114 if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 115 size += sizeof(mt->match_slots[0]) * slots; 116 size += sizeof(mt->matrix[0]) * (slots + 6) * slots; 117 } 118 119 mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO); 120 evdev->ev_mt = mt; 121 122 if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 123 mt->match_slots = mt->slots + slots; 124 mt->matrix = (int *)(mt->match_slots + slots); 125 } 126 127 /* Initialize multitouch protocol type B states */ 128 for (slot = 0; slot < slots; slot++) 129 mt->slots[slot].id = -1; 130 131 if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) 132 evdev_support_abs(evdev, 133 ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0); 134 if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 135 evdev_support_mt_compat(evdev); 136 } 137 138 void 139 evdev_mt_free(struct evdev_dev *evdev) 140 { 141 free(evdev->ev_mt, M_EVDEV); 142 } 143 144 void 145 evdev_mt_sync_frame(struct evdev_dev *evdev) 146 { 147 if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 148 evdev_mt_replay_events(evdev); 149 if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) 150 evdev_mt_send_autorel(evdev); 151 if (evdev->ev_report_opened && 152 bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 153 evdev_mt_send_st_compat(evdev); 154 evdev->ev_mt->frame = 0; 155 } 156 157 static void 158 evdev_mt_send_slot(struct evdev_dev *evdev, int slot, 159 union evdev_mt_slot *state) 160 { 161 int i; 162 bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 163 164 EVDEV_LOCK_ASSERT(evdev); 165 MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev))); 166 MPASS(!type_a || state != NULL); 167 168 if (!type_a) { 169 evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 170 if (state == NULL) { 171 evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1); 172 return; 173 } 174 } 175 bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i) 176 evdev_send_event(evdev, EV_ABS, i, 177 state->val[ABS_MT_INDEX(i)]); 178 if (type_a) 179 evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1); 180 } 181 182 int 183 evdev_mt_push_slot(struct evdev_dev *evdev, int slot, 184 union evdev_mt_slot *state) 185 { 186 struct evdev_mt *mt = evdev->ev_mt; 187 bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 188 189 if (type_a && state == NULL) 190 return (EINVAL); 191 if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev))) 192 return (EINVAL); 193 194 EVDEV_ENTER(evdev); 195 if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 196 evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 197 if (state != NULL) 198 mt->match_slots[mt->match_slot] = *state; 199 else 200 evdev_mt_record_event(evdev, EV_ABS, 201 ABS_MT_TRACKING_ID, -1); 202 } else 203 evdev_mt_send_slot(evdev, slot, state); 204 EVDEV_EXIT(evdev); 205 206 return (0); 207 } 208 209 /* 210 * Find a minimum-weight matching for an m-by-n matrix. 211 * 212 * m must be greater than or equal to n. The size of the buffer must be 213 * at least 3m + 3n. 214 * 215 * On return, the first m elements of the buffer contain the row-to- 216 * column mappings, i.e., buffer[i] is the column index for row i, or -1 217 * if there is no assignment for that row (which may happen if n < m). 218 * 219 * Wrong results because of overflows will not occur with input values 220 * in the range of 0 to INT_MAX / 2 inclusive. 221 * 222 * The function applies the Dinic-Kronrod algorithm. It is not modern or 223 * popular, but it seems to be a good choice for small matrices at least. 224 * The original form of the algorithm is modified as follows: There is no 225 * initial search for row minima, the initial assignments are in a 226 * "virtual" column with the index -1 and zero values. This permits inputs 227 * with n < m, and it simplifies the reassignments. 228 */ 229 static void 230 evdev_mt_matching(int *matrix, int m, int n, int *buffer) 231 { 232 int i, j, k, d, e, row, col, delta; 233 int *p; 234 int *r2c = buffer; /* row-to-column assignments */ 235 int *red = r2c + m; /* reduced values of the assignments */ 236 int *mc = red + m; /* row-wise minimal elements of cs */ 237 int *cs = mc + m; /* the column set */ 238 int *c2r = cs + n; /* column-to-row assignments in cs */ 239 int *cd = c2r + n; /* column deltas (reduction) */ 240 241 for (p = r2c; p < red; *p++ = -1) {} 242 for (; p < mc; *p++ = 0) {} 243 for (col = 0; col < n; col++) { 244 delta = INT_MAX; 245 for (i = 0, p = matrix + col; i < m; i++, p += n) { 246 d = *p - red[i]; 247 if (d < delta || (d == delta && r2c[i] < 0)) { 248 delta = d; 249 row = i; 250 } 251 } 252 cd[col] = delta; 253 if (r2c[row] < 0) { 254 r2c[row] = col; 255 continue; 256 } 257 for (p = mc; p < cs; *p++ = col) {} 258 for (k = 0; (j = r2c[row]) >= 0;) { 259 cs[k++] = j; 260 c2r[j] = row; 261 mc[row] -= n; 262 delta = INT_MAX; 263 for (i = 0, p = matrix; i < m; i++, p += n) 264 if (mc[i] >= 0) { 265 d = p[mc[i]] - cd[mc[i]]; 266 e = p[j] - cd[j]; 267 if (e < d) { 268 d = e; 269 mc[i] = j; 270 } 271 d -= red[i]; 272 if (d < delta || (d == delta 273 && r2c[i] < 0)) { 274 delta = d; 275 row = i; 276 } 277 } 278 cd[col] += delta; 279 for (i = 0; i < k; i++) { 280 cd[cs[i]] += delta; 281 red[c2r[cs[i]]] -= delta; 282 } 283 } 284 for (j = mc[row]; (r2c[row] = j) != col;) { 285 row = c2r[j]; 286 j = mc[row] + n; 287 } 288 } 289 } 290 291 /* 292 * Assign tracking IDs to the points in the pt array. The tracking ID 293 * assignment pairs the points with points of the previous frame in 294 * such a way that the sum of the squared distances is minimal. Using 295 * squares instead of simple distances favours assignments with more uniform 296 * distances, and it is faster. 297 * Set tracking id to -1 for unassigned (new) points. 298 */ 299 void 300 evdev_mt_match_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, 301 int size) 302 { 303 struct evdev_mt *mt = evdev->ev_mt; 304 int i, j, m, n, dx, dy, slot, num_touches; 305 int *p, *r2c, *c2r; 306 307 EVDEV_LOCK_ASSERT(evdev); 308 MPASS(mt->matrix != NULL); 309 MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 310 311 if (size == 0) 312 return; 313 314 p = mt->matrix; 315 num_touches = bitcount(mt->touches); 316 if (num_touches >= size) { 317 FOREACHBIT(mt->touches, slot) 318 for (i = 0; i < size; i++) { 319 dx = pt[i].x - mt->slots[slot].x; 320 dy = pt[i].y - mt->slots[slot].y; 321 *p++ = dx * dx + dy * dy; 322 } 323 m = num_touches; 324 n = size; 325 } else { 326 for (i = 0; i < size; i++) 327 FOREACHBIT(mt->touches, slot) { 328 dx = pt[i].x - mt->slots[slot].x; 329 dy = pt[i].y - mt->slots[slot].y; 330 *p++ = dx * dx + dy * dy; 331 } 332 m = size; 333 n = num_touches; 334 } 335 evdev_mt_matching(mt->matrix, m, n, p); 336 337 r2c = p; 338 c2r = p + m; 339 for (i = 0; i < m; i++) 340 if ((j = r2c[i]) >= 0) 341 c2r[j] = i; 342 343 p = (n == size ? c2r : r2c); 344 for (i = 0; i < size; i++) 345 if (*p++ < 0) 346 pt[i].id = -1; 347 348 p = (n == size ? r2c : c2r); 349 FOREACHBIT(mt->touches, slot) 350 if ((i = *p++) >= 0) 351 pt[i].id = mt->tracking_ids[slot]; 352 } 353 354 static void 355 evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 356 { 357 struct evdev_mt *mt = evdev->ev_mt; 358 union evdev_mt_slot *slot; 359 360 EVDEV_LOCK_ASSERT(evdev); 361 MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 362 363 /* 364 * While MT-matching assign tracking IDs of new contacts to be equal 365 * to a slot number to make things simpler. 366 */ 367 for (slot = pt; slot < pt + size; slot++) { 368 if (slot->id < 0) 369 slot->id = ffc_slot(evdev, mt->touches | mt->frame); 370 if (slot->id >= 0) 371 evdev_mt_send_slot(evdev, slot->id, slot); 372 } 373 } 374 375 int 376 evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 377 { 378 if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1) 379 return (EINVAL); 380 381 EVDEV_ENTER(evdev); 382 evdev_mt_send_frame(evdev, pt, size); 383 EVDEV_EXIT(evdev); 384 385 return (0); 386 } 387 388 bool 389 evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, 390 int32_t value) 391 { 392 struct evdev_mt *mt = evdev->ev_mt; 393 394 EVDEV_LOCK_ASSERT(evdev); 395 396 switch (type) { 397 case EV_ABS: 398 if (code == ABS_MT_SLOT) { 399 /* MT protocol type B support */ 400 KASSERT(value >= 0, ("Negative slot number")); 401 mt->match_slot = value; 402 mt->match_frame |= 1U << mt->match_slot; 403 return (true); 404 } else if (code == ABS_MT_TRACKING_ID) { 405 if (value == -1) 406 mt->match_frame &= ~(1U << mt->match_slot); 407 return (true); 408 } else if (ABS_IS_MT(code)) { 409 KASSERT(mt->match_slot >= 0, ("Negative slot")); 410 KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev), 411 ("Slot number too big")); 412 mt->match_slots[mt->match_slot]. 413 val[ABS_MT_INDEX(code)] = value; 414 return (true); 415 } 416 break; 417 default: 418 break; 419 } 420 421 return (false); 422 } 423 424 static void 425 evdev_mt_replay_events(struct evdev_dev *evdev) 426 { 427 struct evdev_mt *mt = evdev->ev_mt; 428 int slot, size = 0; 429 430 EVDEV_LOCK_ASSERT(evdev); 431 432 FOREACHBIT(mt->match_frame, slot) { 433 if (slot != size) 434 mt->match_slots[size] = mt->match_slots[slot]; 435 size++; 436 } 437 evdev_mt_match_frame(evdev, mt->match_slots, size); 438 evdev_mt_send_frame(evdev, mt->match_slots, size); 439 mt->match_slot = 0; 440 mt->match_frame = 0; 441 } 442 443 union evdev_mt_slot * 444 evdev_mt_get_match_slots(struct evdev_dev *evdev) 445 { 446 return (evdev->ev_mt->match_slots); 447 } 448 449 int 450 evdev_mt_get_last_slot(struct evdev_dev *evdev) 451 { 452 return (evdev->ev_mt->last_reported_slot); 453 } 454 455 void 456 evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) 457 { 458 struct evdev_mt *mt = evdev->ev_mt; 459 460 MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 461 462 mt->frame |= 1U << slot; 463 mt->last_reported_slot = slot; 464 } 465 466 int32_t 467 evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) 468 { 469 struct evdev_mt *mt = evdev->ev_mt; 470 471 MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 472 473 return (mt->slots[slot].val[ABS_MT_INDEX(code)]); 474 } 475 476 void 477 evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, 478 int32_t value) 479 { 480 struct evdev_mt *mt = evdev->ev_mt; 481 482 MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 483 484 if (code == ABS_MT_TRACKING_ID) { 485 if (value != -1) 486 mt->touches |= 1U << slot; 487 else 488 mt->touches &= ~(1U << slot); 489 } 490 mt->slots[slot].val[ABS_MT_INDEX(code)] = value; 491 } 492 493 int 494 evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 495 { 496 struct evdev_mt *mt = evdev->ev_mt; 497 int slot; 498 499 /* 500 * Ignore tracking_id if slot assignment is performed by evdev. 501 * Events are written sequentially to temporary matching buffer. 502 */ 503 if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 504 return (ffc_slot(evdev, mt->match_frame)); 505 506 FOREACHBIT(mt->touches, slot) 507 if (mt->tracking_ids[slot] == tracking_id) 508 return (slot); 509 /* 510 * Do not allow allocation of new slot in a place of just 511 * released one within the same report. 512 */ 513 return (ffc_slot(evdev, mt->touches | mt->frame)); 514 } 515 516 int32_t 517 evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id) 518 { 519 struct evdev_mt *mt = evdev->ev_mt; 520 int32_t nid; 521 522 if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) { 523 mt->tracking_ids[slot] = id; 524 return (id); 525 } 526 527 nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID); 528 if (nid != -1) { 529 KASSERT(id == mt->tracking_ids[slot], 530 ("MT-slot tracking id has changed")); 531 return (nid); 532 } 533 534 mt->tracking_ids[slot] = id; 535 again: 536 nid = mt->tracking_id++; 537 FOREACHBIT(mt->touches, slot) 538 if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid) 539 goto again; 540 541 return (nid); 542 } 543 544 static inline int32_t 545 evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax) 546 { 547 if (stmax != 0 && mtmax != mtmin) { 548 value = (value - mtmin) * stmax / (mtmax - mtmin); 549 value = MAX(MIN(value, stmax), 0); 550 } 551 return (value); 552 } 553 554 void 555 evdev_support_mt_compat(struct evdev_dev *evdev) 556 { 557 struct input_absinfo *ai; 558 int i; 559 560 if (evdev->ev_absinfo == NULL) 561 return; 562 563 evdev_support_event(evdev, EV_KEY); 564 evdev_support_key(evdev, BTN_TOUCH); 565 566 /* Touchscreens should not advertise tap tool capabilities */ 567 if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 568 evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 569 570 /* Echo 0-th MT-slot as ST-slot */ 571 for (i = 0; i < nitems(evdev_mtstmap); i++) { 572 if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) || 573 bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st)) 574 continue; 575 ai = evdev->ev_absinfo + evdev_mtstmap[i].mt; 576 evdev->ev_mt->mtst_events |= 1U << i; 577 if (evdev_mtstmap[i].max != 0) 578 evdev_support_abs(evdev, evdev_mtstmap[i].st, 579 0, 580 evdev_mtstmap[i].max, 581 0, 582 evdev_mt_normalize( 583 ai->flat, 0, ai->maximum, evdev_mtstmap[i].max), 584 0); 585 else 586 evdev_support_abs(evdev, evdev_mtstmap[i].st, 587 ai->minimum, 588 ai->maximum, 589 0, 590 ai->flat, 591 ai->resolution); 592 } 593 } 594 595 static void 596 evdev_mt_send_st_compat(struct evdev_dev *evdev) 597 { 598 struct evdev_mt *mt = evdev->ev_mt; 599 int nfingers, i, st_slot; 600 601 EVDEV_LOCK_ASSERT(evdev); 602 603 nfingers = bitcount(mt->touches); 604 evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 605 606 /* Send first active MT-slot state as single touch report */ 607 st_slot = ffs(mt->touches) - 1; 608 if (st_slot != -1) 609 FOREACHBIT(mt->mtst_events, i) 610 evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st, 611 evdev_mt_normalize(evdev_mt_get_value(evdev, 612 st_slot, evdev_mtstmap[i].mt), 613 evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum, 614 evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum, 615 evdev_mtstmap[i].max)); 616 617 /* Touchscreens should not report tool taps */ 618 if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 619 evdev_send_nfingers(evdev, nfingers); 620 621 if (nfingers == 0) 622 evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 623 } 624 625 void 626 evdev_push_mt_compat(struct evdev_dev *evdev) 627 { 628 629 EVDEV_ENTER(evdev); 630 evdev_mt_send_st_compat(evdev); 631 EVDEV_EXIT(evdev); 632 } 633 634 static void 635 evdev_mt_send_autorel(struct evdev_dev *evdev) 636 { 637 struct evdev_mt *mt = evdev->ev_mt; 638 int slot; 639 640 EVDEV_LOCK_ASSERT(evdev); 641 KASSERT(mt->match_frame == 0, ("Unmatched events exist")); 642 643 FOREACHBIT(mt->touches & ~mt->frame, slot) 644 evdev_mt_send_slot(evdev, slot, NULL); 645 } 646 647 void 648 evdev_mt_push_autorel(struct evdev_dev *evdev) 649 { 650 EVDEV_ENTER(evdev); 651 evdev_mt_send_autorel(evdev); 652 EVDEV_EXIT(evdev); 653 } 654