diff --git a/share/man/man4/btmagic.4 b/share/man/man4/btmagic.4 index 83ea8ceb7443..9a0df071dc07 100644 --- a/share/man/man4/btmagic.4 +++ b/share/man/man4/btmagic.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: btmagic.4,v 1.4 2015/04/06 21:10:31 wiz Exp $ +.\" $NetBSD: btmagic.4,v 1.5 2015/07/03 14:18:18 bouyer Exp $ .\" .\" Copyright (c) 2010 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd April 6, 2015 +.Dd July 4, 2015 .Dt BTMAGIC 4 .Os .Sh NAME @@ -76,7 +76,10 @@ The .Nm driver emulates 3 buttons by splitting the area at the bottom of the device in 3 equal zones and detects finger presence in one of these zones -when the button is pressed. +when the button is pressed. In addition, a tap in any area of the trackpad is interpreted as a left click. The timeout for tap detection defaults to 100ms +and is adjustable with +.Xr sysctl 8 . +.Pp Pointer movement is reported for single-touch movements over the device, and scroll is reported for multi-touch movements. .Pp diff --git a/sys/dev/bluetooth/btmagic.c b/sys/dev/bluetooth/btmagic.c index 3d8b1e1a78fb..22e84956e252 100644 --- a/sys/dev/bluetooth/btmagic.c +++ b/sys/dev/bluetooth/btmagic.c @@ -1,4 +1,4 @@ -/* $NetBSD: btmagic.c,v 1.13 2015/04/16 19:53:19 christos Exp $ */ +/* $NetBSD: btmagic.c,v 1.14 2015/07/03 14:18:18 bouyer Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -85,7 +85,7 @@ *****************************************************************************/ #include -__KERNEL_RCSID(0, "$NetBSD: btmagic.c,v 1.13 2015/04/16 19:53:19 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: btmagic.c,v 1.14 2015/07/03 14:18:18 bouyer Exp $"); #include #include @@ -171,6 +171,11 @@ struct btmagic_softc { /* previous mouse buttons */ int sc_mb_id; /* which ID selects the button */ uint32_t sc_mb; + /* button emulation with tap */ + int sc_tapmb_id; /* which ID selects the button */ + struct timeval sc_taptime; + int sc_taptimeout; + callout_t sc_tapcallout; }; /* sc_flags */ @@ -191,6 +196,8 @@ static int btmagic_listen(struct btmagic_softc *); static int btmagic_connect(struct btmagic_softc *); static int btmagic_sysctl_resolution(SYSCTLFN_PROTO); static int btmagic_sysctl_scale(SYSCTLFN_PROTO); +static int btmagic_tap(struct btmagic_softc *, int); +static int btmagic_sysctl_taptimeout(SYSCTLFN_PROTO); CFATTACH_DECL_NEW(btmagic, sizeof(struct btmagic_softc), btmagic_match, btmagic_attach, btmagic_detach, NULL); @@ -220,6 +227,7 @@ static void btmagic_input(void *, struct mbuf *); static void btmagic_input_basic(struct btmagic_softc *, uint8_t *, size_t); static void btmagic_input_magicm(struct btmagic_softc *, uint8_t *, size_t); static void btmagic_input_magict(struct btmagic_softc *, uint8_t *, size_t); +static void btmagic_tapcallout(void *); /* report types (data[1]) */ #define BASIC_REPORT_ID 0x10 @@ -291,8 +299,12 @@ btmagic_attach(device_t parent, device_t self, void *aux) */ sc->sc_dev = self; sc->sc_state = BTMAGIC_CLOSED; + sc->sc_mb_id = -1; + sc->sc_tapmb_id = -1; callout_init(&sc->sc_timeout, 0); callout_setfunc(&sc->sc_timeout, btmagic_timeout, sc); + callout_init(&sc->sc_tapcallout, 0); + callout_setfunc(&sc->sc_tapcallout, btmagic_tapcallout, sc); sockopt_init(&sc->sc_mode, BTPROTO_L2CAP, SO_L2CAP_LM, 0); /* @@ -332,6 +344,7 @@ btmagic_attach(device_t parent, device_t self, void *aux) sc->sc_firm = 6; sc->sc_dist = 130; sc->sc_scale = 20; + sc->sc_taptimeout = 100; sysctl_createv(&sc->sc_log, 0, NULL, &node, 0, @@ -378,6 +391,14 @@ btmagic_attach(device_t parent, device_t self, void *aux) (void *)sc, 0, CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); + sysctl_createv(&sc->sc_log, 0, NULL, NULL, + CTLFLAG_READWRITE, + CTLTYPE_INT, "taptimeout", + "timeout for tap detection in milliseconds", + btmagic_sysctl_taptimeout, 0, + (void *)sc, 0, + CTL_HW, node->sysctl_num, + CTL_CREATE, CTL_EOL); } /* @@ -437,6 +458,8 @@ btmagic_detach(device_t self, int flags) sc->sc_ctl = NULL; } + callout_halt(&sc->sc_tapcallout, bt_lock); + callout_destroy(&sc->sc_tapcallout); callout_halt(&sc->sc_timeout, bt_lock); callout_destroy(&sc->sc_timeout); @@ -617,6 +640,31 @@ btmagic_sysctl_scale(SYSCTLFN_ARGS) return 0; } +/* validate tap timeout */ +static int +btmagic_sysctl_taptimeout(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct btmagic_softc *sc; + int t, error; + + node = *rnode; + sc = node.sysctl_data; + + t = sc->sc_taptimeout; + node.sysctl_data = &t; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return error; + + if (t < max(1000 / hz, 1) || t > 999) + return EINVAL; + + sc->sc_taptimeout = t; + DPRINTF(sc, "taptimeout = %u", t); + return 0; +} + /***************************************************************************** * * wsmouse(4) accessops @@ -1530,6 +1578,14 @@ btmagic_input_magict(struct btmagic_softc *sc, uint8_t *data, size_t len) ty = ay - sc->sc_ay[id]; if (ISSET(sc->sc_smask, __BIT(id))) { + struct timeval now_tv; + getmicrotime(&now_tv); + if (sc->sc_nfingers == 1 && mb == 0 && + timercmp(&sc->sc_taptime, &now_tv, >)) { + /* still detecting a tap */ + continue; + } + if (sc->sc_nfingers == 1 || mb != 0) { /* single finger moving */ dx += btmagic_scale(tx, &sc->sc_rx, @@ -1548,10 +1604,22 @@ btmagic_input_magict(struct btmagic_softc *sc, uint8_t *data, size_t len) sc->sc_ry = 0; sc->sc_rz = 0; sc->sc_rw = 0; - KASSERT(!ISSET(sc->sc_smask, __BIT(id))); SET(sc->sc_smask, __BIT(id)); sc->sc_nfingers++; + if (sc->sc_tapmb_id == -1 && + mb == 0 && sc->sc_mb == 0) { + sc->sc_tapmb_id = id; + getmicrotime(&sc->sc_taptime); + sc->sc_taptime.tv_usec += + sc->sc_taptimeout * 1000; + if (sc->sc_taptime.tv_usec > 1000000) { + sc->sc_taptime.tv_usec -= + 1000000; + sc->sc_taptime.tv_sec++; + } + } + } break; @@ -1560,6 +1628,9 @@ btmagic_input_magict(struct btmagic_softc *sc, uint8_t *data, size_t len) CLR(sc->sc_smask, __BIT(id)); sc->sc_nfingers--; KASSERT(sc->sc_nfingers >= 0); + if (id == sc->sc_tapmb_id) { + mb = btmagic_tap(sc, id); + } } break; } @@ -1580,3 +1651,38 @@ btmagic_input_magict(struct btmagic_softc *sc, uint8_t *data, size_t len) splx(s); } } + +static int +btmagic_tap(struct btmagic_softc *sc, int id) +{ + struct timeval now_tv; + + sc->sc_tapmb_id = -1; + getmicrotime(&now_tv); + if (timercmp(&sc->sc_taptime, &now_tv, >)) { + /* got a tap */ + callout_schedule( + &sc->sc_tapcallout, + mstohz(sc->sc_taptimeout)); + return __BIT(0); + } + return 0; +} + +static void +btmagic_tapcallout(void *arg) +{ + struct btmagic_softc *sc = arg; + int s; + + mutex_enter(bt_lock); + callout_ack(&sc->sc_tapcallout); + if ((sc->sc_mb & __BIT(0)) != 0) { + sc->sc_mb &= ~__BIT(0); + s = spltty(); + wsmouse_input(sc->sc_wsmouse, sc->sc_mb, + 0, 0, 0, 0, WSMOUSE_INPUT_DELTA); + splx(s); + } + mutex_exit(bt_lock); +}