Lines 3-9
Link Here
|
3 |
* |
3 |
* |
4 |
* This code is derived from software contributed to The DragonFly Project |
4 |
* This code is derived from software contributed to The DragonFly Project |
5 |
* by Matthew Dillon <dillon@backplane.com> and was subsequently ported, |
5 |
* by Matthew Dillon <dillon@backplane.com> and was subsequently ported, |
6 |
* modified and enhanced for FreeBSD by Michael Gmelin <freebsd@grem.de>. |
6 |
* modified and enhanced for FreeBSD by Michael Gmelin <freebsd@grem.de>, |
|
|
7 |
* commonly used gestures added by Alexander Mishurov <ammishurov@gmail.com>. |
7 |
* |
8 |
* |
8 |
* Redistribution and use in source and binary forms, with or without |
9 |
* Redistribution and use in source and binary forms, with or without |
9 |
* modification, are permitted provided that the following conditions |
10 |
* modification, are permitted provided that the following conditions |
Lines 34-40
Link Here
|
34 |
*/ |
35 |
*/ |
35 |
|
36 |
|
36 |
#include <sys/cdefs.h> |
37 |
#include <sys/cdefs.h> |
37 |
__FBSDID("$FreeBSD: head/sys/dev/cyapa/cyapa.c 286918 2015-08-19 09:49:29Z grembo $"); |
38 |
__FBSDID("$FreeBSD$"); |
38 |
|
39 |
|
39 |
/* |
40 |
/* |
40 |
* CYAPA - Cypress APA trackpad with I2C Interface driver |
41 |
* CYAPA - Cypress APA trackpad with I2C Interface driver |
Lines 89-94
Link Here
|
89 |
* event. Optional tap support can be enabled |
90 |
* event. Optional tap support can be enabled |
90 |
* and configured using sysctl. |
91 |
* and configured using sysctl. |
91 |
* |
92 |
* |
|
|
93 |
* Two finger tap - Use two finger tap for right click. |
94 |
* |
95 |
* Tap and drag - Drag through short touching and holding |
96 |
* down a finger on a touchpad. |
97 |
* |
92 |
* WARNINGS |
98 |
* WARNINGS |
93 |
* |
99 |
* |
94 |
* These trackpads get confused when three or more fingers are down on the |
100 |
* These trackpads get confused when three or more fingers are down on the |
Lines 185-190
Link Here
|
185 |
int finger3_ticks; |
191 |
int finger3_ticks; |
186 |
uint16_t reported_but; |
192 |
uint16_t reported_but; |
187 |
|
193 |
|
|
|
194 |
enum {T_IDLE, T_ONE, T_TWO} tft_state; |
195 |
int tft_ticks; |
196 |
enum {D_IDLE, D_WAIT, D_DRAG, D_SEND} drag_state; |
197 |
int dragwait_ticks; |
198 |
int draglock_ticks; |
199 |
uint16_t send_but; |
200 |
|
188 |
struct cyapa_fifo rfifo; /* device->host */ |
201 |
struct cyapa_fifo rfifo; /* device->host */ |
189 |
struct cyapa_fifo wfifo; /* host->device */ |
202 |
struct cyapa_fifo wfifo; /* host->device */ |
190 |
uint8_t ps2_cmd; /* active p2_cmd waiting for data */ |
203 |
uint8_t ps2_cmd; /* active p2_cmd waiting for data */ |
Lines 266-271
Link Here
|
266 |
&cyapa_thumbarea_percent, 0, |
279 |
&cyapa_thumbarea_percent, 0, |
267 |
"Size of bottom thumb area in percent"); |
280 |
"Size of bottom thumb area in percent"); |
268 |
|
281 |
|
|
|
282 |
static int cyapa_enable_tapdrag = 0; |
283 |
SYSCTL_INT(_debug, OID_AUTO, cyapa_enable_tapdrag, CTLFLAG_RW, |
284 |
&cyapa_enable_tapdrag, 0, |
285 |
"Enable tap'n'drag guesture"); |
286 |
static int cyapa_tapdrag_wait_ticks = 15; |
287 |
SYSCTL_INT(_debug, OID_AUTO, cyapa_tapdrag_wait_ticks, CTLFLAG_RW, |
288 |
&cyapa_tapdrag_wait_ticks, 0, |
289 |
"Lock button and wait if it'll be a second tap to lock for drag"); |
290 |
static int cyapa_tapdrag_stick_ticks = 20; |
291 |
SYSCTL_INT(_debug, OID_AUTO, cyapa_tapdrag_stick_ticks, CTLFLAG_RW, |
292 |
&cyapa_tapdrag_stick_ticks, 0, |
293 |
"Time to keep button locked after stopped moving while drag"); |
294 |
static int cyapa_tapdrag_doubleclick_ticks = 30; |
295 |
SYSCTL_INT(_debug, OID_AUTO, cyapa_tapdrag_doubleclick_ticks, CTLFLAG_RW, |
296 |
&cyapa_tapdrag_doubleclick_ticks, 0, |
297 |
"Duration when second finger release can send double click"); |
298 |
|
269 |
static int cyapa_debug = 0; |
299 |
static int cyapa_debug = 0; |
270 |
SYSCTL_INT(_debug, OID_AUTO, cyapa_debug, CTLFLAG_RW, |
300 |
SYSCTL_INT(_debug, OID_AUTO, cyapa_debug, CTLFLAG_RW, |
271 |
&cyapa_debug, 0, "Enable debugging"); |
301 |
&cyapa_debug, 0, "Enable debugging"); |
Lines 524-529
Link Here
|
524 |
sc->mode.level = 0; |
554 |
sc->mode.level = 0; |
525 |
sc->mode.packetsize = MOUSE_PS2_PACKETSIZE; |
555 |
sc->mode.packetsize = MOUSE_PS2_PACKETSIZE; |
526 |
|
556 |
|
|
|
557 |
sc->drag_state = D_IDLE; |
558 |
sc->draglock_ticks = -1; |
559 |
sc->dragwait_ticks = -1; |
560 |
sc->tft_state = T_IDLE; |
561 |
sc->tft_ticks = -1; |
562 |
sc->send_but = 0; |
563 |
|
527 |
/* Setup input event tracking */ |
564 |
/* Setup input event tracking */ |
528 |
cyapa_set_power_mode(sc, CMD_POWER_MODE_IDLE); |
565 |
cyapa_set_power_mode(sc, CMD_POWER_MODE_IDLE); |
529 |
|
566 |
|
Lines 536-541
Link Here
|
536 |
|
573 |
|
537 |
sc->devnode->si_drv1 = sc; |
574 |
sc->devnode->si_drv1 = sc; |
538 |
|
575 |
|
|
|
576 |
|
539 |
return (0); |
577 |
return (0); |
540 |
} |
578 |
} |
541 |
|
579 |
|
Lines 1256-1263
Link Here
|
1256 |
int x; |
1294 |
int x; |
1257 |
int y; |
1295 |
int y; |
1258 |
int z; |
1296 |
int z; |
1259 |
int newfinger; |
1297 |
int deltafingers; |
1260 |
int lessfingers; |
|
|
1261 |
int click_x; |
1298 |
int click_x; |
1262 |
int click_y; |
1299 |
int click_y; |
1263 |
uint16_t but; /* high bits used for simulated but4/but5 */ |
1300 |
uint16_t but; /* high bits used for simulated but4/but5 */ |
Lines 1341-1348
Link Here
|
1341 |
sc->finger3_ticks = sc->poll_ticks; |
1378 |
sc->finger3_ticks = sc->poll_ticks; |
1342 |
break; |
1379 |
break; |
1343 |
} |
1380 |
} |
1344 |
newfinger = sc->track_nfingers < afingers; |
1381 |
deltafingers = afingers - sc->track_nfingers; |
1345 |
lessfingers = sc->track_nfingers > afingers; |
|
|
1346 |
sc->track_nfingers = afingers; |
1382 |
sc->track_nfingers = afingers; |
1347 |
|
1383 |
|
1348 |
/* |
1384 |
/* |
Lines 1392-1406
Link Here
|
1392 |
sc->track_id = regs->touch[i].id; |
1428 |
sc->track_id = regs->touch[i].id; |
1393 |
} |
1429 |
} |
1394 |
else if ((sc->track_but || |
1430 |
else if ((sc->track_but || |
1395 |
CYAPA_TOUCH_Y(regs, i) >= thumbarea_begin) && |
1431 |
CYAPA_TOUCH_Y(regs, i) >= thumbarea_begin) && |
1396 |
newfinger && afingers == 2) { |
1432 |
deltafingers > 0 && afingers == 2) { |
1397 |
j = regs->touch[0].id == sc->track_id ? 1 : 0; |
1433 |
j = regs->touch[0].id == sc->track_id ? 1 : 0; |
1398 |
if (CYAPA_TOUCH_Y(regs, j) < thumbarea_begin) { |
1434 |
if (CYAPA_TOUCH_Y(regs, j) < thumbarea_begin) { |
1399 |
i = j; |
1435 |
i = j; |
1400 |
sc->track_x = -1; |
1436 |
sc->track_x = -1; |
1401 |
sc->track_y = -1; |
1437 |
sc->track_y = -1; |
1402 |
sc->track_z = -1; |
1438 |
sc->track_z = -1; |
1403 |
sc->track_id = regs->touch[i].id; |
1439 |
sc->track_id = regs->touch[i].id; |
1404 |
} |
1440 |
} |
1405 |
} |
1441 |
} |
1406 |
} |
1442 |
} |
Lines 1466-1479
Link Here
|
1466 |
sc->track_y = y; |
1502 |
sc->track_y = y; |
1467 |
} |
1503 |
} |
1468 |
|
1504 |
|
|
|
1505 |
/* |
1506 |
* Double down |
1507 |
* Because it's hard every time touch and release fingers |
1508 |
* in exact same moment, there's some time range to detect |
1509 |
* random sequence of 0-1-2-1-0 touches and interpret them as |
1510 |
* right click then make some additional checks to |
1511 |
* don't confuse touches with two finger scroll |
1512 |
*/ |
1513 |
int is_tapclick = 0; |
1514 |
|
1515 |
if (cyapa_enable_tapclick == 4) { |
1516 |
switch(sc->tft_state) { |
1517 |
case T_IDLE: |
1518 |
if (deltafingers > 0 && sc->track_z == -1 && |
1519 |
sc->delta_z == 0) { |
1520 |
if (deltafingers == 1 && afingers == 1) { |
1521 |
sc->tft_ticks = sc->poll_ticks; |
1522 |
sc->tft_state = T_ONE; |
1523 |
} else if (deltafingers == 2 && afingers == 2) { |
1524 |
sc->tft_ticks = sc->poll_ticks; |
1525 |
sc->tft_state = T_TWO; |
1526 |
} |
1527 |
} |
1528 |
break; |
1529 |
case T_ONE: |
1530 |
if (sc->poll_ticks - sc->tft_ticks > |
1531 |
cyapa_tapclick_max_ticks || afingers == 0 || |
1532 |
sc->delta_z != 0) { |
1533 |
sc->tft_ticks = -1; |
1534 |
sc->tft_state = T_IDLE; |
1535 |
} else if (deltafingers == 1 && afingers == 2) { |
1536 |
sc->tft_state = T_TWO; |
1537 |
} |
1538 |
break; |
1539 |
case T_TWO: |
1540 |
if (sc->poll_ticks - sc->tft_ticks > |
1541 |
cyapa_tapclick_max_ticks || sc->delta_z != 0) { |
1542 |
sc->tft_ticks = -1; |
1543 |
sc->tft_state = T_IDLE; |
1544 |
} else if (deltafingers < 0 && afingers == 0 && |
1545 |
sc->track_z == -1 && sc->poll_ticks - |
1546 |
sc->tft_ticks >= cyapa_tapclick_min_ticks) { |
1547 |
sc->tft_ticks = -1; |
1548 |
sc->tft_state = T_IDLE; |
1549 |
is_tapclick = 2; |
1550 |
} |
1551 |
break; |
1552 |
} |
1553 |
} |
1554 |
|
1469 |
/* Select finger (L = 2/3x, M = 1/3u, R = 1/3d) */ |
1555 |
/* Select finger (L = 2/3x, M = 1/3u, R = 1/3d) */ |
1470 |
int is_tapclick = (cyapa_enable_tapclick && lessfingers && |
1556 |
if (cyapa_enable_tapclick && is_tapclick == 0 && deltafingers == -1 && |
1471 |
afingers == 0 && sc->poll_ticks - sc->finger1_ticks |
1557 |
afingers == 0 && sc->poll_ticks - sc->finger1_ticks |
1472 |
>= cyapa_tapclick_min_ticks && |
1558 |
>= cyapa_tapclick_min_ticks && sc->poll_ticks - sc->finger1_ticks |
1473 |
sc->poll_ticks - sc->finger1_ticks < cyapa_tapclick_max_ticks); |
1559 |
< cyapa_tapclick_max_ticks) |
|
|
1560 |
is_tapclick = 1; |
1474 |
|
1561 |
|
1475 |
if (regs->fngr & CYAPA_FNGR_LEFT || is_tapclick) { |
1562 |
if (regs->fngr & CYAPA_FNGR_LEFT || is_tapclick) { |
1476 |
if (sc->track_but) { |
1563 |
if (is_tapclick == 2) { |
|
|
1564 |
but = CYAPA_FNGR_RIGHT; |
1565 |
} else if (sc->track_but) { |
1477 |
but = sc->track_but; |
1566 |
but = sc->track_but; |
1478 |
} else if (afingers == 1) { |
1567 |
} else if (afingers == 1) { |
1479 |
if (click_x < sc->cap_resx * 2 / 3) |
1568 |
if (click_x < sc->cap_resx * 2 / 3) |
Lines 1482-1490
Link Here
|
1482 |
but = CYAPA_FNGR_MIDDLE; |
1571 |
but = CYAPA_FNGR_MIDDLE; |
1483 |
else |
1572 |
else |
1484 |
but = CYAPA_FNGR_RIGHT; |
1573 |
but = CYAPA_FNGR_RIGHT; |
1485 |
} else if (is_tapclick) { |
1574 |
} else if (is_tapclick == 1) { |
1486 |
if (click_x < sc->cap_resx * 2 / 3 || |
1575 |
if (click_x < sc->cap_resx * 2 / 3 || |
1487 |
cyapa_enable_tapclick < 2) |
1576 |
cyapa_enable_tapclick < 2 || |
|
|
1577 |
cyapa_enable_tapclick == 4) |
1488 |
but = CYAPA_FNGR_LEFT; |
1578 |
but = CYAPA_FNGR_LEFT; |
1489 |
else if (click_y < sc->cap_resy / 2 && |
1579 |
else if (click_y < sc->cap_resy / 2 && |
1490 |
cyapa_enable_tapclick > 2) |
1580 |
cyapa_enable_tapclick > 2) |
Lines 1499-1510
Link Here
|
1499 |
} |
1589 |
} |
1500 |
|
1590 |
|
1501 |
/* |
1591 |
/* |
|
|
1592 |
* Drag n Lock |
1593 |
* Finit-state machine states (sc->drag_state): |
1594 |
* IDLE - idle mode, waits any event |
1595 |
* WAIT - locks button and waits for second tap, releases if timeout |
1596 |
* DRAG - locks button and drags, releases if moves stopped or finger up |
1597 |
* SEND - sends double click sequence if double click instead drag |
1598 |
* In WAIT or DRAG mode double click could be sent if touch and release |
1599 |
*/ |
1600 |
|
1601 |
if (cyapa_enable_tapdrag) { |
1602 |
/* Handle double click the same way in two states */ |
1603 |
if (sc->drag_state == D_SEND) { |
1604 |
but = sc->send_but; |
1605 |
sc->send_but = 0; |
1606 |
} |
1607 |
/* User can lock any button only with left button mouse */ |
1608 |
if ((sc->drag_state == D_WAIT || sc->drag_state == D_DRAG) && |
1609 |
((sc->poll_ticks - sc->dragwait_ticks <= |
1610 |
cyapa_tapdrag_doubleclick_ticks && but == |
1611 |
CYAPA_FNGR_LEFT) || (but == CYAPA_FNGR_RIGHT || |
1612 |
but == CYAPA_FNGR_MIDDLE))) { |
1613 |
sc->draglock_ticks = -1; |
1614 |
sc->dragwait_ticks = -1; |
1615 |
sc->send_but = but; |
1616 |
sc->drag_state = D_SEND; |
1617 |
but = 0; |
1618 |
} |
1619 |
|
1620 |
/* Handle particular states */ |
1621 |
switch(sc->drag_state) { |
1622 |
case D_IDLE: |
1623 |
if (but == CYAPA_FNGR_LEFT || but == CYAPA_FNGR_RIGHT || |
1624 |
but == CYAPA_FNGR_MIDDLE) { |
1625 |
sc->send_but = but; |
1626 |
sc->dragwait_ticks = sc->poll_ticks; |
1627 |
sc->drag_state = D_WAIT; |
1628 |
} |
1629 |
break; |
1630 |
case D_WAIT: |
1631 |
if (sc->poll_ticks - sc->dragwait_ticks > |
1632 |
cyapa_tapdrag_wait_ticks || sc->delta_z != 0) { |
1633 |
sc->dragwait_ticks = -1; |
1634 |
sc->send_but = 0; |
1635 |
sc->drag_state = D_IDLE; |
1636 |
} else if (deltafingers == 1 && afingers == 1) { |
1637 |
sc->draglock_ticks = sc->poll_ticks; |
1638 |
sc->drag_state = D_DRAG; |
1639 |
but = sc->send_but; |
1640 |
} else { |
1641 |
but = sc->send_but; |
1642 |
} |
1643 |
break; |
1644 |
case D_DRAG: |
1645 |
if (sc->poll_ticks - sc->draglock_ticks > |
1646 |
cyapa_tapdrag_stick_ticks || deltafingers < 0 || |
1647 |
sc->delta_z != 0) { |
1648 |
sc->dragwait_ticks = -1; |
1649 |
sc->draglock_ticks = -1; |
1650 |
sc->send_but = 0; |
1651 |
sc->drag_state = D_IDLE; |
1652 |
} else { |
1653 |
if (sc->delta_x || sc->delta_y) |
1654 |
sc->draglock_ticks = sc->poll_ticks; |
1655 |
but = sc->send_but; |
1656 |
} |
1657 |
break; |
1658 |
case D_SEND: |
1659 |
if (sc->send_but == 0) |
1660 |
sc->drag_state = D_IDLE; |
1661 |
break; |
1662 |
} |
1663 |
} |
1664 |
|
1665 |
/* |
1502 |
* Detect state change from last reported state and |
1666 |
* Detect state change from last reported state and |
1503 |
* determine if we have gone idle. |
1667 |
* determine if we have gone idle. |
1504 |
*/ |
1668 |
*/ |
1505 |
sc->track_but = but; |
1669 |
sc->track_but = but; |
1506 |
if (sc->delta_x || sc->delta_y || sc->delta_z || |
1670 |
if (sc->delta_z || sc->delta_y || sc->delta_x || |
1507 |
sc->track_but != sc->reported_but) { |
1671 |
sc->track_but != sc->reported_but || sc->send_but != 0) { |
1508 |
sc->active_tick = ticks; |
1672 |
sc->active_tick = ticks; |
1509 |
if (sc->remote_mode == 0 && sc->reporting_mode) |
1673 |
if (sc->remote_mode == 0 && sc->reporting_mode) |
1510 |
sc->data_signal = 1; |
1674 |
sc->data_signal = 1; |