[BACK]Return to synaptics.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pckbport

Annotation of src/sys/dev/pckbport/synaptics.c, Revision 1.47

1.47    ! blymn       1: /*     $NetBSD: synaptics.c,v 1.46 2018/12/04 10:10:15 blymn Exp $     */
1.1       christos    2:
                      3: /*
1.3       scw         4:  * Copyright (c) 2005, Steve C. Woodford
1.1       christos    5:  * Copyright (c) 2004, Ales Krenek
                      6:  * Copyright (c) 2004, Kentaro A. Kurahone
                      7:  * All rights reserved.
1.5       perry       8:  *
1.1       christos    9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  *
                     13:  *   * Redistributions of source code must retain the above copyright
                     14:  *     notice, this list of conditions and the following disclaimer.
                     15:  *   * Redistributions in binary form must reproduce the above
                     16:  *     copyright notice, this list of conditions and the following
                     17:  *     disclaimer in the documentation and/or other materials provided
                     18:  *     with the distribution.
                     19:  *   * Neither the name of the authors nor the names of its
                     20:  *     contributors may be used to endorse or promote products derived
                     21:  *     from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     24:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     25:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
                     26:  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
                     27:  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
                     28:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     29:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     30:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
                     31:  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     33:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     34:  * POSSIBILITY OF SUCH DAMAGE.
                     35:  *
                     36:  */
                     37:
1.3       scw        38: /*
                     39:  * TODO:
                     40:  *     - Make the sysctl values per-instance instead of global.
                     41:  *     - Consider setting initial scaling factors at runtime according
                     42:  *       to the values returned by the 'Read Resolutions' command.
                     43:  *     - Support the serial protocol (we only support PS/2 for now)
                     44:  *     - Support auto-repeat for up/down button Z-axis emulation.
                     45:  *     - Maybe add some more gestures (can we use Palm support somehow?)
                     46:  */
                     47:
1.4       scw        48: #include "opt_pms.h"
                     49:
1.1       christos   50: #include <sys/cdefs.h>
1.47    ! blymn      51: __KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.46 2018/12/04 10:10:15 blymn Exp $");
1.1       christos   52:
                     53: #include <sys/param.h>
                     54: #include <sys/systm.h>
                     55: #include <sys/device.h>
                     56: #include <sys/ioctl.h>
                     57: #include <sys/sysctl.h>
                     58: #include <sys/kernel.h>
1.25      uebayasi   59: #include <sys/proc.h>
1.1       christos   60:
1.16      ad         61: #include <sys/bus.h>
1.1       christos   62:
                     63: #include <dev/pckbport/pckbportvar.h>
                     64:
                     65: #include <dev/pckbport/synapticsreg.h>
                     66: #include <dev/pckbport/synapticsvar.h>
                     67:
                     68: #include <dev/pckbport/pmsreg.h>
                     69: #include <dev/pckbport/pmsvar.h>
                     70:
                     71: #include <dev/wscons/wsconsio.h>
                     72: #include <dev/wscons/wsmousevar.h>
                     73:
1.3       scw        74: /*
                     75:  * Absolute-mode packets are decoded and passed around using
                     76:  * the following structure.
                     77:  */
                     78: struct synaptics_packet {
                     79:        signed short    sp_x;   /* Unscaled absolute X/Y coordinates */
                     80:        signed short    sp_y;
                     81:        u_char  sp_z;           /* Z (pressure) */
                     82:        u_char  sp_w;           /* W (contact patch width) */
1.34      blymn      83:        signed short    sp_sx;  /* Secondary finger unscaled absolute */
                     84:                                /* X/Y coordinates */
                     85:        signed short    sp_xy;
                     86:        u_char  sp_finger;      /* 0 for primary, 1 for secondary */
1.3       scw        87:        char    sp_left;        /* Left mouse button status */
                     88:        char    sp_right;       /* Right mouse button status */
                     89:        char    sp_middle;      /* Middle button status (possibly emulated) */
                     90:        char    sp_up;          /* Up button status */
                     91:        char    sp_down;        /* Down button status */
                     92: };
                     93:
1.1       christos   94: static void pms_synaptics_input(void *, int);
1.3       scw        95: static void pms_synaptics_process_packet(struct pms_softc *,
                     96:                struct synaptics_packet *);
1.2       christos   97: static void pms_sysctl_synaptics(struct sysctllog **);
1.1       christos   98: static int pms_sysctl_synaptics_verify(SYSCTLFN_ARGS);
                     99:
1.28      jakllsch  100: /* Controlled by sysctl. */
1.3       scw       101: static int synaptics_up_down_emul = 2;
                    102: static int synaptics_up_down_motion_delta = 1;
                    103: static int synaptics_gesture_move = 200;
                    104: static int synaptics_gesture_length = 20;
                    105: static int synaptics_edge_left = SYNAPTICS_EDGE_LEFT;
                    106: static int synaptics_edge_right = SYNAPTICS_EDGE_RIGHT;
                    107: static int synaptics_edge_top = SYNAPTICS_EDGE_TOP;
                    108: static int synaptics_edge_bottom = SYNAPTICS_EDGE_BOTTOM;
                    109: static int synaptics_edge_motion_delta = 32;
                    110: static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5;
                    111: static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10;
1.34      blymn     112: static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720;
                    113: static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3;
                    114: static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3;
1.3       scw       115: static int synaptics_two_fingers_emul = 0;
                    116: static int synaptics_scale_x = 16;
                    117: static int synaptics_scale_y = 16;
1.46      blymn     118: static int synaptics_scale_z = 32;
1.3       scw       119: static int synaptics_max_speed_x = 32;
                    120: static int synaptics_max_speed_y = 32;
1.44      blymn     121: static int synaptics_max_speed_z = 2;
1.3       scw       122: static int synaptics_movement_threshold = 4;
1.45      blymn     123: static int synaptics_fscroll_min = 13;
                    124: static int synaptics_fscroll_max = 14;
1.44      blymn     125: static int synaptics_dz_hold = 30;
1.36      jmcneill  126: static int synaptics_movement_enable = 1;
1.1       christos  127:
                    128: /* Sysctl nodes. */
1.34      blymn     129: static int synaptics_button_boundary_nodenum;
                    130: static int synaptics_button2_nodenum;
                    131: static int synaptics_button3_nodenum;
1.3       scw       132: static int synaptics_up_down_emul_nodenum;
                    133: static int synaptics_up_down_motion_delta_nodenum;
                    134: static int synaptics_gesture_move_nodenum;
                    135: static int synaptics_gesture_length_nodenum;
                    136: static int synaptics_edge_left_nodenum;
                    137: static int synaptics_edge_right_nodenum;
                    138: static int synaptics_edge_top_nodenum;
                    139: static int synaptics_edge_bottom_nodenum;
                    140: static int synaptics_edge_motion_delta_nodenum;
                    141: static int synaptics_finger_high_nodenum;
                    142: static int synaptics_finger_low_nodenum;
                    143: static int synaptics_two_fingers_emul_nodenum;
                    144: static int synaptics_scale_x_nodenum;
                    145: static int synaptics_scale_y_nodenum;
1.44      blymn     146: static int synaptics_scale_z_nodenum;
1.3       scw       147: static int synaptics_max_speed_x_nodenum;
                    148: static int synaptics_max_speed_y_nodenum;
1.44      blymn     149: static int synaptics_max_speed_z_nodenum;
1.3       scw       150: static int synaptics_movement_threshold_nodenum;
1.44      blymn     151: static int synaptics_finger_scroll_min_nodenum;
                    152: static int synaptics_finger_scroll_max_nodenum;
                    153: static int synaptics_dz_hold_nodenum;
1.36      jmcneill  154: static int synaptics_movement_enable_nodenum;
1.1       christos  155:
1.34      blymn     156: static int
                    157: synaptics_poll_cmd(struct pms_softc *psc, ...)
                    158: {
                    159:        u_char cmd[4];
                    160:        size_t i;
                    161:        va_list ap;
                    162:
                    163:        va_start(ap, psc);
                    164:
                    165:        for (i = 0; i < __arraycount(cmd); i++)
                    166:                if ((cmd[i] = (u_char)va_arg(ap, int)) == 0)
                    167:                        break;
                    168:        va_end(ap);
                    169:
                    170:        int res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, i, 0,
                    171:            NULL, 0);
                    172:        if (res)
                    173:                aprint_error_dev(psc->sc_dev, "command error %#x\n", cmd[0]);
                    174:        return res;
                    175: }
                    176:
                    177: static int
                    178: synaptics_poll_reset(struct pms_softc *psc)
                    179: {
                    180:        u_char resp[2];
                    181:        int res;
                    182:
                    183:        u_char cmd[1] = { PMS_RESET };
                    184:        res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2,
                    185:            resp, 1);
                    186:        aprint_debug_dev(psc->sc_dev, "reset %d 0x%02x 0x%02x\n",
                    187:            res, resp[0], resp[1]);
                    188:        return res;
                    189: }
                    190:
                    191: static int
1.42      maya      192: synaptics_special_read(struct pms_softc *psc, u_char slice, u_char resp[3])
1.34      blymn     193: {
                    194:        u_char cmd[1] = { PMS_SEND_DEV_STATUS };
                    195:        int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, slice);
                    196:
                    197:        return res | pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
                    198:            cmd, 1, 3, resp, 0);
                    199: }
                    200:
1.42      maya      201: static int
                    202: synaptics_special_write(struct pms_softc *psc, u_char command, u_char arg)
                    203: {
                    204:        int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, arg);
                    205:        if (res)
                    206:                return res;
                    207:
                    208:        u_char cmd[2];
                    209:        cmd[0] = PMS_SET_SAMPLE;
                    210:        cmd[1] = command;
                    211:        res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
                    212:            cmd, 2, 0, NULL, 0);
                    213:        return res;
                    214: }
                    215:
1.32      christos  216: static void
                    217: pms_synaptics_probe_extended(struct pms_softc *psc)
                    218: {
                    219:        struct synaptics_softc *sc = &psc->u.synaptics;
1.34      blymn     220:        u_char resp[3];
1.32      christos  221:        int res;
                    222:
                    223:        aprint_debug_dev(psc->sc_dev,
                    224:            "synaptics_probe: Capabilities 0x%04x.\n", sc->caps);
                    225:        if (sc->caps & SYNAPTICS_CAP_PASSTHROUGH)
                    226:                sc->flags |= SYN_FLAG_HAS_PASSTHROUGH;
                    227:
                    228:        if (sc->caps & SYNAPTICS_CAP_PALMDETECT)
                    229:                sc->flags |= SYN_FLAG_HAS_PALM_DETECT;
                    230:
                    231:        if (sc->caps & SYNAPTICS_CAP_MULTIDETECT)
                    232:                sc->flags |= SYN_FLAG_HAS_MULTI_FINGER;
                    233:
                    234:        if (sc->caps & SYNAPTICS_CAP_MULTIFINGERREPORT)
                    235:                sc->flags |= SYN_FLAG_HAS_MULTI_FINGER_REPORT;
                    236:
                    237:        /* Ask about extra buttons to detect up/down. */
                    238:        if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08)
                    239:            >= SYNAPTICS_EXTENDED_QUERY)
                    240:        {
1.42      maya      241:                res = synaptics_special_read(psc, SYNAPTICS_EXTENDED_QUERY, resp);
1.32      christos  242:                if (res == 0) {
                    243:                        int buttons = (resp[1] >> 4);
                    244:                        aprint_debug_dev(psc->sc_dev,
                    245:                            "%s: Extended Buttons: %d.\n", __func__, buttons);
                    246:
                    247:                        aprint_debug_dev(psc->sc_dev, "%s: Extended "
                    248:                            "Capabilities: 0x%02x 0x%02x 0x%02x.\n", __func__,
                    249:                            resp[0], resp[1], resp[2]);
                    250:                        if (buttons >= 2) {
                    251:                                /* Yes. */
                    252:                                sc->flags |= SYN_FLAG_HAS_UP_DOWN_BUTTONS;
                    253:                        }
                    254:                        if (resp[0] & 0x1) {
                    255:                                /* Vertical scroll area */
                    256:                                sc->flags |= SYN_FLAG_HAS_VERTICAL_SCROLL;
                    257:                        }
                    258:                        if (resp[0] & 0x2) {
                    259:                                /* Horizontal scroll area */
                    260:                                sc->flags |= SYN_FLAG_HAS_HORIZONTAL_SCROLL;
                    261:                        }
                    262:                        if (resp[0] & 0x4) {
                    263:                                /* Extended W-Mode */
                    264:                                sc->flags |= SYN_FLAG_HAS_EXTENDED_WMODE;
                    265:                        }
                    266:                }
                    267:        }
                    268:
                    269:        /* Ask about click pad */
                    270:        if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >=
                    271:            SYNAPTICS_CONTINUED_CAPABILITIES)
                    272:        {
1.42      maya      273:                res = synaptics_special_read(psc,
1.34      blymn     274:                    SYNAPTICS_CONTINUED_CAPABILITIES, resp);
                    275:
1.33      christos  276: /*
                    277:  * The following describes response for the
                    278:  * SYNAPTICS_CONTINUED_CAPABILITIES query.
                    279:  *
                    280:  * byte        mask    name                    meaning
                    281:  * ----        ----    -------                 ------------
                    282:  * 0   0x01    adjustable threshold    capacitive button sensitivity
                    283:  *                                     can be adjusted
                    284:  * 0   0x02    report max              query 0x0d gives max coord reported
                    285:  * 0   0x04    clearpad                sensor is ClearPad product
                    286:  * 0   0x08    advanced gesture        not particularly meaningful
                    287:  * 0   0x10    clickpad bit 0          1-button ClickPad
                    288:  * 0   0x60    multifinger mode        identifies firmware finger counting
                    289:  *                                     (not reporting!) algorithm.
                    290:  *                                     Not particularly meaningful
                    291:  * 0   0x80    covered pad             W clipped to 14, 15 == pad mostly covered
                    292:  * 1   0x01    clickpad bit 1          2-button ClickPad
                    293:  * 1   0x02    deluxe LED controls     touchpad support LED commands
                    294:  *                                     ala multimedia control bar
                    295:  * 1   0x04    reduced filtering       firmware does less filtering on
                    296:  *                                     position data, driver should watch
                    297:  *                                     for noise.
                    298:  * 1   0x08    image sensor            image sensor tracks 5 fingers, but only
                    299:  *                                     reports 2.
1.47    ! blymn     300:  * 1   0x10    uniform clickpad        whole clickpad moves instead of being
1.33      christos  301:  *                                     hinged at the top.
                    302:  * 1   0x20    report min              query 0x0f gives min coord reported
                    303:  */
1.32      christos  304:                if (res == 0) {
1.33      christos  305:                        u_char clickpad_type = (resp[0] & 0x10);
                    306:                        clickpad_type |=       (resp[1] & 0x01);
1.32      christos  307:
                    308:                        aprint_debug_dev(psc->sc_dev, "%s: Continued "
                    309:                            "Capabilities 0x%02x 0x%02x 0x%02x.\n", __func__,
                    310:                            resp[0], resp[1], resp[2]);
                    311:                        switch (clickpad_type) {
1.33      christos  312:                        case 0x10:
1.32      christos  313:                                sc->flags |= SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD;
                    314:                                break;
1.33      christos  315:                        case 0x01:
1.32      christos  316:                                sc->flags |= SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD;
                    317:                                break;
                    318:                        default:
                    319:                                break;
                    320:                        }
                    321:                }
                    322:        }
                    323: }
                    324:
1.40      christos  325: static const struct {
                    326:        int bit;
                    327:        const char *desc;
                    328: } syn_flags[] = {
                    329:        { SYN_FLAG_HAS_EXTENDED_WMODE, "Extended W mode", },
                    330:        { SYN_FLAG_HAS_PASSTHROUGH, "Passthrough", },
                    331:        { SYN_FLAG_HAS_MIDDLE_BUTTON, "Middle button", },
                    332:        { SYN_FLAG_HAS_BUTTONS_4_5, "Buttons 4/5", },
                    333:        { SYN_FLAG_HAS_UP_DOWN_BUTTONS, "Up/down buttons", },
                    334:        { SYN_FLAG_HAS_PALM_DETECT, "Palm detect", },
                    335:        { SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD, "One button click pad", },
                    336:        { SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD, "Two button click pad", },
                    337:        { SYN_FLAG_HAS_VERTICAL_SCROLL, "Vertical scroll", },
                    338:        { SYN_FLAG_HAS_HORIZONTAL_SCROLL, "Horizontal scroll", },
                    339:        { SYN_FLAG_HAS_MULTI_FINGER_REPORT, "Multi-finger Report", },
                    340:        { SYN_FLAG_HAS_MULTI_FINGER, "Multi-finger", },
                    341: };
                    342:
1.1       christos  343: int
                    344: pms_synaptics_probe_init(void *vsc)
                    345: {
1.3       scw       346:        struct pms_softc *psc = vsc;
                    347:        struct synaptics_softc *sc = &psc->u.synaptics;
1.28      jakllsch  348:        u_char cmd[1], resp[3];
1.3       scw       349:        int res, ver_minor, ver_major;
1.2       christos  350:        struct sysctllog *clog = NULL;
1.1       christos  351:
1.27      jakllsch  352:        res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot,
1.1       christos  353:            SYNAPTICS_IDENTIFY_TOUCHPAD);
                    354:        cmd[0] = PMS_SEND_DEV_STATUS;
1.3       scw       355:        res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3,
                    356:            resp, 0);
1.1       christos  357:        if (res) {
1.26      cegger    358:                aprint_debug_dev(psc->sc_dev,
1.20      cube      359:                    "synaptics_probe: Identify Touchpad error.\n");
1.3       scw       360:                /*
                    361:                 * Reset device in case the probe confused it.
                    362:                 */
                    363:  doreset:
1.35      ryoon     364:                (void)synaptics_poll_reset(psc);
                    365:                return res;
1.1       christos  366:        }
                    367:
                    368:        if (resp[1] != SYNAPTICS_MAGIC_BYTE) {
1.26      cegger    369:                aprint_debug_dev(psc->sc_dev,
1.20      cube      370:                    "synaptics_probe: Not synaptics.\n");
1.3       scw       371:                res = 1;
                    372:                goto doreset;
1.1       christos  373:        }
                    374:
1.3       scw       375:        sc->flags = 0;
                    376:
1.1       christos  377:        /* Check for minimum version and print a nice message. */
                    378:        ver_major = resp[2] & 0x0f;
                    379:        ver_minor = resp[0];
1.20      cube      380:        aprint_normal_dev(psc->sc_dev, "Synaptics touchpad version %d.%d\n",
                    381:            ver_major, ver_minor);
1.1       christos  382:        if (ver_major * 10 + ver_minor < SYNAPTICS_MIN_VERSION) {
                    383:                /* No capability query support. */
1.3       scw       384:                sc->caps = 0;
1.1       christos  385:                goto done;
                    386:        }
                    387:
1.34      blymn     388:
1.1       christos  389:        /* Query the hardware capabilities. */
1.42      maya      390:        res = synaptics_special_read(psc, SYNAPTICS_READ_CAPABILITIES, resp);
1.1       christos  391:        if (res) {
                    392:                /* Hmm, failed to get capabilites. */
1.20      cube      393:                aprint_error_dev(psc->sc_dev,
                    394:                    "synaptics_probe: Failed to query capabilities.\n");
1.3       scw       395:                goto doreset;
1.1       christos  396:        }
                    397:
1.3       scw       398:        sc->caps = (resp[0] << 8) | resp[2];
                    399:
                    400:        if (sc->caps & SYNAPTICS_CAP_MBUTTON)
                    401:                sc->flags |= SYN_FLAG_HAS_MIDDLE_BUTTON;
                    402:
                    403:        if (sc->caps & SYNAPTICS_CAP_4BUTTON)
                    404:                sc->flags |= SYN_FLAG_HAS_BUTTONS_4_5;
                    405:
                    406:        if (sc->caps & SYNAPTICS_CAP_EXTENDED) {
1.32      christos  407:                pms_synaptics_probe_extended(psc);
1.3       scw       408:        }
                    409:
                    410:        if (sc->flags) {
                    411:                const char comma[] = ", ";
                    412:                const char *sep = "";
1.20      cube      413:                aprint_normal_dev(psc->sc_dev, "");
1.40      christos  414:                for (size_t f = 0; f < __arraycount(syn_flags); f++) {
                    415:                        if (sc->flags & syn_flags[f].bit) {
                    416:                                aprint_normal("%s%s", sep, syn_flags[f].desc);
                    417:                                sep = comma;
                    418:                        }
1.3       scw       419:                }
1.41      christos  420:                aprint_normal("\n");
1.1       christos  421:        }
                    422:
                    423: done:
1.2       christos  424:        pms_sysctl_synaptics(&clog);
1.3       scw       425:        pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot,
1.20      cube      426:            pms_synaptics_input, psc, device_xname(psc->sc_dev));
1.3       scw       427:
                    428:        return (0);
1.1       christos  429: }
                    430:
                    431: void
                    432: pms_synaptics_enable(void *vsc)
                    433: {
1.3       scw       434:        struct pms_softc *psc = vsc;
                    435:        struct synaptics_softc *sc = &psc->u.synaptics;
1.34      blymn     436:        u_char enable_modes;
1.44      blymn     437:        int res, i;
1.1       christos  438:
1.23      plunky    439:        if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) {
1.32      christos  440:                /*
1.40      christos  441:                 * Extended capability probes can confuse the passthrough
                    442:                 * device; reset the touchpad now to cure that.
1.23      plunky    443:                 */
1.34      blymn     444:                res = synaptics_poll_reset(psc);
1.23      plunky    445:        }
                    446:
1.3       scw       447:        /*
                    448:         * Enable Absolute mode with W (width) reporting, and set
1.34      blymn     449:         * the packet rate to maximum (80 packets per second). Enable
                    450:         * extended W mode if supported so we can report second finger
                    451:         * position.
1.3       scw       452:         */
1.34      blymn     453:        enable_modes =
                    454:           SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE;
                    455:
1.38      ryoon     456:        if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE)
1.34      blymn     457:                enable_modes |= SYNAPTICS_MODE_EXTENDED_W;
                    458:
                    459:        /*
                    460:        * Synaptics documentation says to disable device before
                    461:        * setting mode.
                    462:        */
                    463:        synaptics_poll_cmd(psc, PMS_DEV_DISABLE, 0);
                    464:        /* a couple of set scales to clear out pending commands */
1.44      blymn     465:        for (i = 0; i < 2; i++)
1.34      blymn     466:                synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0);
                    467:
1.42      maya      468:        res = synaptics_special_write(psc, SYNAPTICS_CMD_SET_MODE2, enable_modes);
1.34      blymn     469:        if (res)
                    470:                aprint_error("synaptics: set mode error\n");
                    471:
                    472:        /* a couple of set scales to clear out pending commands */
1.44      blymn     473:        for (i = 0; i < 2; i++)
1.34      blymn     474:                synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0);
                    475:
1.42      maya      476:        /* Set advanced gesture mode */
                    477:        if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE)
                    478:                synaptics_special_write(psc, SYNAPTICS_WRITE_DELUXE_3, 0x3);
1.39      ryoon     479:
1.34      blymn     480:        synaptics_poll_cmd(psc, PMS_DEV_ENABLE, 0);
                    481:
1.3       scw       482:        sc->up_down = 0;
                    483:        sc->prev_fingers = 0;
                    484:        sc->gesture_start_x = sc->gesture_start_y = 0;
                    485:        sc->gesture_start_packet = 0;
                    486:        sc->gesture_tap_packet = 0;
                    487:        sc->gesture_type = 0;
                    488:        sc->gesture_buttons = 0;
1.44      blymn     489:        sc->dz_hold = 0;
                    490:        for (i = 0; i < SYN_MAX_FINGERS; i++) {
                    491:                sc->rem_x[i] = sc->rem_y[i] = sc->rem_z[i] = 0;
                    492:                sc->movement_history[i] = 0;
                    493:        }
1.34      blymn     494:        sc->button_history = 0;
1.1       christos  495: }
                    496:
                    497: void
                    498: pms_synaptics_resume(void *vsc)
                    499: {
1.34      blymn     500:        (void)synaptics_poll_reset(vsc);
1.1       christos  501: }
                    502:
1.3       scw       503: static void
                    504: pms_sysctl_synaptics(struct sysctllog **clog)
1.1       christos  505: {
                    506:        int rc, root_num;
1.6       atatat    507:        const struct sysctlnode *node;
1.1       christos  508:
                    509:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    510:            CTLFLAG_PERMANENT, CTLTYPE_NODE, "synaptics",
                    511:            SYSCTL_DESCR("Synaptics touchpad controls"),
                    512:            NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
                    513:            goto err;
                    514:
                    515:        root_num = node->sysctl_num;
                    516:
                    517:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    518:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.3       scw       519:            CTLTYPE_INT, "up_down_emulation",
                    520:            SYSCTL_DESCR("Middle button/Z-axis emulation with up/down buttons"),
                    521:            pms_sysctl_synaptics_verify, 0,
                    522:            &synaptics_up_down_emul,
                    523:            0, CTL_HW, root_num, CTL_CREATE,
                    524:            CTL_EOL)) != 0)
                    525:                goto err;
                    526:
                    527:        synaptics_up_down_emul_nodenum = node->sysctl_num;
                    528:
                    529:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    530:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    531:            CTLTYPE_INT, "up_down_motion_delta",
                    532:            SYSCTL_DESCR("Up/down button Z-axis emulation rate"),
                    533:            pms_sysctl_synaptics_verify, 0,
                    534:            &synaptics_up_down_motion_delta,
                    535:            0, CTL_HW, root_num, CTL_CREATE,
                    536:            CTL_EOL)) != 0)
                    537:                goto err;
                    538:
                    539:        synaptics_up_down_motion_delta_nodenum = node->sysctl_num;
                    540:
                    541:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    542:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    543:            CTLTYPE_INT, "gesture_move",
                    544:            SYSCTL_DESCR("Movement greater than this between taps cancels gesture"),
                    545:            pms_sysctl_synaptics_verify, 0,
                    546:            &synaptics_gesture_move,
                    547:            0, CTL_HW, root_num, CTL_CREATE,
                    548:            CTL_EOL)) != 0)
                    549:                goto err;
                    550:
                    551:        synaptics_gesture_move_nodenum = node->sysctl_num;
                    552:
                    553:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    554:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    555:            CTLTYPE_INT, "gesture_length",
                    556:            SYSCTL_DESCR("Time period in which tap is recognised as a gesture"),
                    557:            pms_sysctl_synaptics_verify, 0,
                    558:            &synaptics_gesture_length,
                    559:            0, CTL_HW, root_num, CTL_CREATE,
                    560:            CTL_EOL)) != 0)
                    561:                goto err;
                    562:
                    563:        synaptics_gesture_length_nodenum = node->sysctl_num;
                    564:
                    565:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    566:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    567:            CTLTYPE_INT, "edge_left",
                    568:            SYSCTL_DESCR("Define left edge of touchpad"),
                    569:            pms_sysctl_synaptics_verify, 0,
                    570:            &synaptics_edge_left,
                    571:            0, CTL_HW, root_num, CTL_CREATE,
                    572:            CTL_EOL)) != 0)
                    573:                goto err;
                    574:
                    575:        synaptics_edge_left_nodenum = node->sysctl_num;
                    576:
                    577:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    578:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    579:            CTLTYPE_INT, "edge_right",
                    580:            SYSCTL_DESCR("Define right edge of touchpad"),
1.1       christos  581:            pms_sysctl_synaptics_verify, 0,
1.3       scw       582:            &synaptics_edge_right,
1.1       christos  583:            0, CTL_HW, root_num, CTL_CREATE,
                    584:            CTL_EOL)) != 0)
                    585:                goto err;
                    586:
1.3       scw       587:        synaptics_edge_right_nodenum = node->sysctl_num;
1.1       christos  588:
                    589:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    590:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.3       scw       591:            CTLTYPE_INT, "edge_top",
                    592:            SYSCTL_DESCR("Define top edge of touchpad"),
1.1       christos  593:            pms_sysctl_synaptics_verify, 0,
1.3       scw       594:            &synaptics_edge_top,
1.1       christos  595:            0, CTL_HW, root_num, CTL_CREATE,
                    596:            CTL_EOL)) != 0)
1.3       scw       597:                goto err;
                    598:
                    599:        synaptics_edge_top_nodenum = node->sysctl_num;
                    600:
                    601:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    602:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    603:            CTLTYPE_INT, "edge_bottom",
                    604:            SYSCTL_DESCR("Define bottom edge of touchpad"),
                    605:            pms_sysctl_synaptics_verify, 0,
                    606:            &synaptics_edge_bottom,
                    607:            0, CTL_HW, root_num, CTL_CREATE,
                    608:            CTL_EOL)) != 0)
                    609:                goto err;
                    610:
                    611:        synaptics_edge_bottom_nodenum = node->sysctl_num;
                    612:
                    613:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    614:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    615:            CTLTYPE_INT, "edge_motion_delta",
                    616:            SYSCTL_DESCR("Define edge motion rate"),
                    617:            pms_sysctl_synaptics_verify, 0,
                    618:            &synaptics_edge_motion_delta,
                    619:            0, CTL_HW, root_num, CTL_CREATE,
                    620:            CTL_EOL)) != 0)
                    621:                goto err;
                    622:
                    623:        synaptics_edge_motion_delta_nodenum = node->sysctl_num;
                    624:
                    625:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    626:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    627:            CTLTYPE_INT, "finger_high",
                    628:            SYSCTL_DESCR("Define finger applied pressure threshold"),
                    629:            pms_sysctl_synaptics_verify, 0,
                    630:            &synaptics_finger_high,
                    631:            0, CTL_HW, root_num, CTL_CREATE,
                    632:            CTL_EOL)) != 0)
                    633:                goto err;
                    634:
                    635:        synaptics_finger_high_nodenum = node->sysctl_num;
                    636:
                    637:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    638:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    639:            CTLTYPE_INT, "finger_low",
                    640:            SYSCTL_DESCR("Define finger removed pressure threshold"),
                    641:            pms_sysctl_synaptics_verify, 0,
                    642:            &synaptics_finger_low,
                    643:            0, CTL_HW, root_num, CTL_CREATE,
                    644:            CTL_EOL)) != 0)
                    645:                goto err;
                    646:
                    647:        synaptics_finger_low_nodenum = node->sysctl_num;
                    648:
                    649:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    650:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    651:            CTLTYPE_INT, "two_fingers_emulation",
                    652:            SYSCTL_DESCR("Map two fingers to middle button"),
                    653:            pms_sysctl_synaptics_verify, 0,
                    654:            &synaptics_two_fingers_emul,
                    655:            0, CTL_HW, root_num, CTL_CREATE,
                    656:            CTL_EOL)) != 0)
                    657:                goto err;
                    658:
                    659:        synaptics_two_fingers_emul_nodenum = node->sysctl_num;
                    660:
                    661:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    662:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    663:            CTLTYPE_INT, "scale_x",
                    664:            SYSCTL_DESCR("Horizontal movement scale factor"),
                    665:            pms_sysctl_synaptics_verify, 0,
1.30      dsl       666:            &synaptics_scale_x,
1.3       scw       667:            0, CTL_HW, root_num, CTL_CREATE,
                    668:            CTL_EOL)) != 0)
                    669:                goto err;
                    670:
                    671:        synaptics_scale_x_nodenum = node->sysctl_num;
                    672:
                    673:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    674:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    675:            CTLTYPE_INT, "scale_y",
                    676:            SYSCTL_DESCR("Vertical movement scale factor"),
                    677:            pms_sysctl_synaptics_verify, 0,
1.30      dsl       678:            &synaptics_scale_y,
1.3       scw       679:            0, CTL_HW, root_num, CTL_CREATE,
                    680:            CTL_EOL)) != 0)
                    681:                goto err;
1.1       christos  682:
1.3       scw       683:        synaptics_scale_y_nodenum = node->sysctl_num;
1.1       christos  684:
                    685:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    686:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.44      blymn     687:            CTLTYPE_INT, "scale_z",
                    688:            SYSCTL_DESCR("Sroll wheel emulation scale factor"),
                    689:            pms_sysctl_synaptics_verify, 0,
                    690:            &synaptics_scale_z,
                    691:            0, CTL_HW, root_num, CTL_CREATE,
                    692:            CTL_EOL)) != 0)
                    693:                goto err;
                    694:
                    695:        synaptics_scale_z_nodenum = node->sysctl_num;
                    696:
                    697:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    698:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.3       scw       699:            CTLTYPE_INT, "max_speed_x",
                    700:            SYSCTL_DESCR("Horizontal movement maximum speed"),
1.1       christos  701:            pms_sysctl_synaptics_verify, 0,
1.3       scw       702:            &synaptics_max_speed_x,
1.1       christos  703:            0, CTL_HW, root_num, CTL_CREATE,
                    704:            CTL_EOL)) != 0)
                    705:                goto err;
                    706:
1.3       scw       707:        synaptics_max_speed_x_nodenum = node->sysctl_num;
1.1       christos  708:
                    709:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    710:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.3       scw       711:            CTLTYPE_INT, "max_speed_y",
                    712:            SYSCTL_DESCR("Vertical movement maximum speed"),
1.1       christos  713:            pms_sysctl_synaptics_verify, 0,
1.3       scw       714:            &synaptics_max_speed_y,
1.1       christos  715:            0, CTL_HW, root_num, CTL_CREATE,
                    716:            CTL_EOL)) != 0)
                    717:                goto err;
                    718:
1.3       scw       719:        synaptics_max_speed_y_nodenum = node->sysctl_num;
1.1       christos  720:
                    721:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    722:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.44      blymn     723:            CTLTYPE_INT, "max_speed_z",
                    724:            SYSCTL_DESCR("Scroll wheel emulation maximum speed"),
                    725:            pms_sysctl_synaptics_verify, 0,
                    726:            &synaptics_max_speed_z,
                    727:            0, CTL_HW, root_num, CTL_CREATE,
                    728:            CTL_EOL)) != 0)
                    729:                goto err;
                    730:
                    731:        synaptics_max_speed_z_nodenum = node->sysctl_num;
                    732:
                    733:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    734:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.3       scw       735:            CTLTYPE_INT, "movement_threshold",
                    736:            SYSCTL_DESCR("Minimum reported movement threshold"),
1.1       christos  737:            pms_sysctl_synaptics_verify, 0,
1.3       scw       738:            &synaptics_movement_threshold,
1.1       christos  739:            0, CTL_HW, root_num, CTL_CREATE,
                    740:            CTL_EOL)) != 0)
                    741:                goto err;
                    742:
1.3       scw       743:        synaptics_movement_threshold_nodenum = node->sysctl_num;
1.34      blymn     744:
                    745:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    746:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.36      jmcneill  747:            CTLTYPE_INT, "movement_enable",
                    748:            SYSCTL_DESCR("Enable movement reporting"),
                    749:            pms_sysctl_synaptics_verify, 0,
                    750:            &synaptics_movement_enable,
                    751:            0, CTL_HW, root_num, CTL_CREATE,
                    752:            CTL_EOL)) != 0)
                    753:                goto err;
                    754:
                    755:        synaptics_movement_enable_nodenum = node->sysctl_num;
                    756:
                    757:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    758:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1.34      blymn     759:            CTLTYPE_INT, "button_boundary",
                    760:            SYSCTL_DESCR("Top edge of button area"),
                    761:            pms_sysctl_synaptics_verify, 0,
                    762:            &synaptics_button_boundary,
                    763:            0, CTL_HW, root_num, CTL_CREATE,
                    764:            CTL_EOL)) != 0)
                    765:                goto err;
                    766:
                    767:        synaptics_button_boundary_nodenum = node->sysctl_num;
                    768:
                    769:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    770:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    771:            CTLTYPE_INT, "button2_edge",
                    772:            SYSCTL_DESCR("Left edge of button 2 region"),
                    773:            pms_sysctl_synaptics_verify, 0,
                    774:            &synaptics_button2,
                    775:            0, CTL_HW, root_num, CTL_CREATE,
                    776:            CTL_EOL)) != 0)
                    777:                goto err;
                    778:
                    779:        synaptics_button2_nodenum = node->sysctl_num;
                    780:
                    781:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    782:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    783:            CTLTYPE_INT, "button3_edge",
                    784:            SYSCTL_DESCR("Left edge of button 3 region"),
                    785:            pms_sysctl_synaptics_verify, 0,
                    786:            &synaptics_button3,
                    787:            0, CTL_HW, root_num, CTL_CREATE,
                    788:            CTL_EOL)) != 0)
                    789:                goto err;
                    790:
                    791:        synaptics_button3_nodenum = node->sysctl_num;
1.44      blymn     792:
                    793:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    794:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    795:            CTLTYPE_INT, "finger_scroll-min",
1.45      blymn     796:            SYSCTL_DESCR("Minimum width at which y cursor movements will be converted to scroll wheel events"),
1.44      blymn     797:            pms_sysctl_synaptics_verify, 0,
                    798:            &synaptics_fscroll_min,
                    799:            0, CTL_HW, root_num, CTL_CREATE,
                    800:            CTL_EOL)) != 0)
                    801:                goto err;
                    802:
                    803:        synaptics_finger_scroll_min_nodenum = node->sysctl_num;
                    804:
                    805:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    806:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    807:            CTLTYPE_INT, "finger_scroll-max",
1.45      blymn     808:            SYSCTL_DESCR("Maximum width at which y cursor movements will be converted to scroll wheel events"),
1.44      blymn     809:            pms_sysctl_synaptics_verify, 0,
                    810:            &synaptics_fscroll_max,
                    811:            0, CTL_HW, root_num, CTL_CREATE,
                    812:            CTL_EOL)) != 0)
                    813:                goto err;
                    814:
                    815:        synaptics_finger_scroll_max_nodenum = node->sysctl_num;
                    816:
                    817:        if ((rc = sysctl_createv(clog, 0, NULL, &node,
                    818:            CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
                    819:            CTLTYPE_INT, "finger_scroll-hysteresis",
1.45      blymn     820:            SYSCTL_DESCR("Number of packets to keep reporting y cursor movements as scroll wheel events"),
1.44      blymn     821:            pms_sysctl_synaptics_verify, 0,
                    822:            &synaptics_dz_hold,
                    823:            0, CTL_HW, root_num, CTL_CREATE,
                    824:            CTL_EOL)) != 0)
                    825:                goto err;
                    826:
                    827:        synaptics_dz_hold_nodenum = node->sysctl_num;
1.1       christos  828:        return;
                    829:
                    830: err:
1.3       scw       831:        aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
1.1       christos  832: }
                    833:
                    834: static int
                    835: pms_sysctl_synaptics_verify(SYSCTLFN_ARGS)
                    836: {
                    837:        int error, t;
                    838:        struct sysctlnode node;
                    839:
                    840:        node = *rnode;
                    841:        t = *(int *)rnode->sysctl_data;
                    842:        node.sysctl_data = &t;
                    843:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    844:        if (error || newp == NULL)
                    845:                return error;
                    846:
                    847:        /* Sanity check the params. */
1.3       scw       848:        if (node.sysctl_num == synaptics_up_down_emul_nodenum ||
                    849:            node.sysctl_num == synaptics_two_fingers_emul_nodenum) {
                    850:                if (t < 0 || t > 2)
                    851:                        return (EINVAL);
                    852:        } else
                    853:        if (node.sysctl_num == synaptics_gesture_length_nodenum ||
                    854:            node.sysctl_num == synaptics_edge_motion_delta_nodenum ||
                    855:            node.sysctl_num == synaptics_up_down_motion_delta_nodenum) {
1.1       christos  856:                if (t < 0)
1.3       scw       857:                        return (EINVAL);
                    858:        } else
                    859:        if (node.sysctl_num == synaptics_edge_left_nodenum ||
                    860:            node.sysctl_num == synaptics_edge_bottom_nodenum) {
                    861:                if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 2))
                    862:                        return (EINVAL);
                    863:        } else
                    864:        if (node.sysctl_num == synaptics_edge_right_nodenum ||
                    865:            node.sysctl_num == synaptics_edge_top_nodenum) {
                    866:                if (t < (SYNAPTICS_EDGE_MAX / 2))
                    867:                        return (EINVAL);
1.1       christos  868:        } else
1.3       scw       869:        if (node.sysctl_num == synaptics_scale_x_nodenum ||
1.46      blymn     870:            node.sysctl_num == synaptics_scale_y_nodenum ||
                    871:            node.sysctl_num == synaptics_scale_z_nodenum) {
1.3       scw       872:                if (t < 1 || t > (SYNAPTICS_EDGE_MAX / 4))
                    873:                        return (EINVAL);
                    874:        } else
                    875:        if (node.sysctl_num == synaptics_finger_high_nodenum) {
                    876:                if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
                    877:                    t < synaptics_finger_low)
                    878:                        return (EINVAL);
                    879:        } else
                    880:        if (node.sysctl_num == synaptics_finger_low_nodenum) {
                    881:                if (t < 0 || t > SYNAPTICS_FINGER_PALM ||
                    882:                    t > synaptics_finger_high)
                    883:                        return (EINVAL);
                    884:        } else
                    885:        if (node.sysctl_num == synaptics_gesture_move_nodenum ||
                    886:            node.sysctl_num == synaptics_movement_threshold_nodenum) {
                    887:                if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4))
                    888:                        return (EINVAL);
                    889:        } else
1.36      jmcneill  890:        if (node.sysctl_num == synaptics_button_boundary_nodenum) {
1.38      ryoon     891:                if (t < 0 || t < SYNAPTICS_EDGE_BOTTOM ||
1.34      blymn     892:                    t > SYNAPTICS_EDGE_TOP)
                    893:                        return (EINVAL);
                    894:        } else
1.36      jmcneill  895:        if (node.sysctl_num == synaptics_button2_nodenum ||
                    896:            node.sysctl_num == synaptics_button3_nodenum) {
1.34      blymn     897:                if (t < SYNAPTICS_EDGE_LEFT || t > SYNAPTICS_EDGE_RIGHT)
                    898:                        return (EINVAL);
                    899:        } else
1.44      blymn     900:        if (node.sysctl_num == synaptics_finger_scroll_min_nodenum ||
                    901:            node.sysctl_num == synaptics_finger_scroll_max_nodenum) {
                    902:                /* make sure we avoid the "magic" widths, 4 and below
                    903:                   are for fingers, 15 is palm detect. */
                    904:                if ((t < 5) || (t > 14))
                    905:                        return (EINVAL);
                    906:        } else
1.45      blymn     907:        if (node.sysctl_num == synaptics_dz_hold_nodenum) {
                    908:                if (t < 0)
                    909:                        return (EINVAL);
                    910:        } else
1.36      jmcneill  911:        if (node.sysctl_num == synaptics_movement_enable_nodenum) {
                    912:                if (t < 0 || t > 1)
                    913:                        return (EINVAL);
                    914:        } else
1.3       scw       915:                return (EINVAL);
1.1       christos  916:
1.3       scw       917:        *(int *)rnode->sysctl_data = t;
1.1       christos  918:
1.3       scw       919:        return (0);
1.1       christos  920: }
                    921:
1.3       scw       922: /* Masks for the first byte of a packet */
                    923: #define PMS_LBUTMASK 0x01
                    924: #define PMS_RBUTMASK 0x02
                    925: #define PMS_MBUTMASK 0x04
1.1       christos  926:
                    927: static void
1.14      mlelstv   928: pms_synaptics_parse(struct pms_softc *psc)
                    929: {
                    930:        struct synaptics_softc *sc = &psc->u.synaptics;
                    931:        struct synaptics_packet sp;
1.34      blymn     932:        char new_buttons, ew_mode;
1.14      mlelstv   933:
1.32      christos  934:        memset(&sp, 0, sizeof(sp));
                    935:
1.14      mlelstv   936:        /* Width of finger */
                    937:        sp.sp_w = ((psc->packet[0] & 0x30) >> 2) +
                    938:           ((psc->packet[0] & 0x04) >> 1) +
                    939:           ((psc->packet[3] & 0x04) >> 2);
1.34      blymn     940:        sp.sp_finger = 0;
1.38      ryoon     941:        if (sp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W) {
1.34      blymn     942:                ew_mode = psc->packet[5] >> 4;
                    943:                switch (ew_mode)
                    944:                {
                    945:                case SYNAPTICS_EW_WHEEL:
                    946:                        /* scroll wheel report, ignore for now */
                    947:                        aprint_debug_dev(psc->sc_dev, "mouse wheel packet\n");
                    948:                        return;
1.14      mlelstv   949:
1.34      blymn     950:                case SYNAPTICS_EW_SECONDARY_FINGER:
                    951:                        /* parse the second finger report */
                    952:
                    953:                        sp.sp_finger = 1; /* just one other finger for now */
                    954:                        sp.sp_x = psc->packet[1]
                    955:                            + ((psc->packet[4] & 0x0f) << 8);
                    956:                        sp.sp_y = psc->packet[2]
                    957:                            + ((psc->packet[4] & 0xf0) << 4);
                    958:                        sp.sp_z = (psc->packet[3] & 0x30)
                    959:                            + (psc->packet[5] & 0x0f);
                    960:
                    961:                        /* keep same buttons down as primary */
                    962:                        sp.sp_left = sc->button_history & PMS_LBUTMASK;
                    963:                        sp.sp_middle = sc->button_history & PMS_MBUTMASK;
                    964:                        sp.sp_right = sc->button_history & PMS_RBUTMASK;
                    965:                        break;
                    966:
                    967:                case SYNAPTICS_EW_FINGER_STATUS:
                    968:                        /* reports which finger is primary/secondary
                    969:                         * ignore for now.
                    970:                         */
                    971:                        return;
                    972:
                    973:                default:
                    974:                        aprint_error_dev(psc->sc_dev,
                    975:                            "invalid extended w mode %d\n",
                    976:                            ew_mode);
                    977:                        return;
                    978:                }
1.14      mlelstv   979:        } else {
1.34      blymn     980:
                    981:                /* Absolute X/Y coordinates of finger */
                    982:                sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) +
                    983:                ((psc->packet[3] & 0x10) << 8);
                    984:                sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) +
                    985:                ((psc->packet[3] & 0x20) << 7);
                    986:
                    987:                /* Pressure */
                    988:                sp.sp_z = psc->packet[2];
                    989:
                    990:                /* Left/Right button handling. */
                    991:                sp.sp_left = psc->packet[0] & PMS_LBUTMASK;
                    992:                sp.sp_right = psc->packet[0] & PMS_RBUTMASK;
                    993:
                    994:                /* Up/Down buttons. */
                    995:                if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) {
                    996:                        /* Old up/down buttons. */
                    997:                        sp.sp_up = sp.sp_left ^
                    998:                            (psc->packet[3] & PMS_LBUTMASK);
                    999:                        sp.sp_down = sp.sp_right ^
                   1000:                            (psc->packet[3] & PMS_RBUTMASK);
                   1001:                } else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS &&
                   1002:                    ((psc->packet[0] & PMS_RBUTMASK) ^
                   1003:                    (psc->packet[3] & PMS_RBUTMASK))) {
                   1004:                        /* New up/down button. */
                   1005:                        sp.sp_up = psc->packet[4] & SYN_1BUTMASK;
                   1006:                        sp.sp_down = psc->packet[5] & SYN_2BUTMASK;
                   1007:                } else {
                   1008:                        sp.sp_up = 0;
                   1009:                        sp.sp_down = 0;
                   1010:                }
                   1011:
                   1012:                new_buttons = 0;
                   1013:                if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) {
                   1014:                        /* This is not correctly specified. Read this button press
1.38      ryoon    1015:                        * from L/U bit.  Emulate 3 buttons by checking the
1.34      blymn    1016:                        * coordinates of the click and returning the appropriate
                   1017:                        * button code.  Outside the button region default to a
                   1018:                        * left click.
                   1019:                        */
                   1020:                        u_char bstate = (psc->packet[0] ^ psc->packet[3])
                   1021:                                            & 0x01;
                   1022:                        if (sp.sp_y < synaptics_button_boundary) {
                   1023:                                if (sp.sp_x > synaptics_button3) {
                   1024:                                        sp.sp_right =
                   1025:                                                bstate ? PMS_RBUTMASK : 0;
                   1026:                                } else if (sp.sp_x > synaptics_button2) {
                   1027:                                        sp.sp_middle =
                   1028:                                                bstate ? PMS_MBUTMASK : 0;
                   1029:                                } else {
                   1030:                                        sp.sp_left = bstate ? PMS_LBUTMASK : 0;
                   1031:                                }
                   1032:                        } else
                   1033:                                sp.sp_left = bstate ? 1 : 0;
                   1034:                        new_buttons = sp.sp_left | sp.sp_middle | sp.sp_right;
                   1035:                        if (new_buttons != sc->button_history) {
                   1036:                                if (sc->button_history == 0)
                   1037:                                        sc->button_history = new_buttons;
                   1038:                                else if (new_buttons == 0) {
                   1039:                                        sc->button_history = 0;
                   1040:                                       /* ensure all buttons are cleared just in
                   1041:                                        * case finger comes off in a different
                   1042:                                        * region.
                   1043:                                        */
                   1044:                                        sp.sp_left = 0;
                   1045:                                        sp.sp_middle = 0;
                   1046:                                        sp.sp_right = 0;
                   1047:                                } else {
                   1048:                                        /* make sure we keep the same button even
                   1049:                                        * if the finger moves to a different
                   1050:                                        * region.  This precludes chording
                   1051:                                        * but, oh well.
                   1052:                                        */
                   1053:                                        sp.sp_left = sc->button_history & PMS_LBUTMASK;
                   1054:                                        sp.sp_middle = sc->button_history
                   1055:                                        & PMS_MBUTMASK;
                   1056:                                        sp.sp_right = sc->button_history & PMS_RBUTMASK;
                   1057:                                }
                   1058:                        }
                   1059:                } else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) {
                   1060:                        /* Old style Middle Button. */
                   1061:                        sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^
                   1062:                            (psc->packet[3] & PMS_LBUTMASK);
                   1063:                } else if (synaptics_up_down_emul == 1) {
                   1064:                        /* Do middle button emulation using up/down buttons */
                   1065:                        sp.sp_middle = sp.sp_up | sp.sp_down;
                   1066:                        sp.sp_up = sp.sp_down = 0;
                   1067:                } else
                   1068:                        sp.sp_middle = 0;
                   1069:
1.14      mlelstv  1070:        }
                   1071:
                   1072:        pms_synaptics_process_packet(psc, &sp);
                   1073: }
                   1074:
                   1075: static void
                   1076: pms_synaptics_passthrough(struct pms_softc *psc)
                   1077: {
                   1078:        int dx, dy, dz;
                   1079:        int buttons, changed;
                   1080:        int s;
                   1081:
                   1082:        buttons = ((psc->packet[1] & PMS_LBUTMASK) ? 0x20 : 0) |
                   1083:                ((psc->packet[1] & PMS_MBUTMASK) ? 0x40 : 0) |
                   1084:                ((psc->packet[1] & PMS_RBUTMASK) ? 0x80 : 0);
                   1085:
                   1086:        dx = psc->packet[4];
                   1087:        if (dx >= 128)
                   1088:                dx -= 256;
                   1089:        if (dx == -128)
                   1090:                dx = -127;
                   1091:
                   1092:        dy = psc->packet[5];
                   1093:        if (dy >= 128)
                   1094:                dy -= 256;
                   1095:        if (dy == -128)
                   1096:                dy = -127;
                   1097:
                   1098:        dz = 0;
                   1099:
                   1100:        changed = buttons ^ (psc->buttons & 0xe0);
                   1101:        psc->buttons ^= changed;
                   1102:
                   1103:        if (dx || dy || dz || changed) {
                   1104:                buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
                   1105:                s = spltty();
                   1106:                wsmouse_input(psc->sc_wsmousedev,
1.15      mlelstv  1107:                        buttons, dx, dy, dz, 0,
1.14      mlelstv  1108:                        WSMOUSE_INPUT_DELTA);
                   1109:                splx(s);
                   1110:        }
                   1111: }
                   1112:
                   1113: static void
1.1       christos 1114: pms_synaptics_input(void *vsc, int data)
                   1115: {
1.3       scw      1116:        struct pms_softc *psc = vsc;
                   1117:        struct timeval diff;
1.1       christos 1118:
1.3       scw      1119:        if (!psc->sc_enabled) {
1.28      jakllsch 1120:                /* Interrupts are not expected. Discard the byte. */
1.1       christos 1121:                return;
                   1122:        }
                   1123:
1.10      kardel   1124:        getmicrouptime(&psc->current);
1.1       christos 1125:
1.3       scw      1126:        if (psc->inputstate > 0) {
                   1127:                timersub(&psc->current, &psc->last, &diff);
1.1       christos 1128:                if (diff.tv_sec > 0 || diff.tv_usec >= 40000) {
1.20      cube     1129:                        aprint_debug_dev(psc->sc_dev,
                   1130:                            "pms_input: unusual delay (%ld.%06ld s), "
                   1131:                            "scheduling reset\n",
1.1       christos 1132:                            (long)diff.tv_sec, (long)diff.tv_usec);
1.34      blymn    1133:                        printf("pms_input: unusual delay (%ld.%06ld s), "
                   1134:                            "scheduling reset\n",
                   1135:                            (long)diff.tv_sec, (long)diff.tv_usec);
1.3       scw      1136:                        psc->inputstate = 0;
                   1137:                        psc->sc_enabled = 0;
                   1138:                        wakeup(&psc->sc_enabled);
1.1       christos 1139:                        return;
                   1140:                }
                   1141:        }
1.3       scw      1142:        psc->last = psc->current;
1.1       christos 1143:
1.3       scw      1144:        switch (psc->inputstate) {
                   1145:        case 0:
1.1       christos 1146:                if ((data & 0xc8) != 0x80) {
1.26      cegger   1147:                        aprint_debug_dev(psc->sc_dev,
1.20      cube     1148:                            "pms_input: 0x%02x out of sync\n", data);
1.1       christos 1149:                        return; /* not in sync yet, discard input */
                   1150:                }
1.3       scw      1151:                /*FALLTHROUGH*/
                   1152:
                   1153:        case 3:
1.5       perry    1154:                if ((data & 8) == 8) {
1.26      cegger   1155:                        aprint_debug_dev(psc->sc_dev,
1.20      cube     1156:                            "pms_input: dropped in relative mode, reset\n");
1.3       scw      1157:                        psc->inputstate = 0;
                   1158:                        psc->sc_enabled = 0;
                   1159:                        wakeup(&psc->sc_enabled);
1.1       christos 1160:                        return;
                   1161:                }
                   1162:        }
                   1163:
1.3       scw      1164:        psc->packet[psc->inputstate++] = data & 0xff;
                   1165:        if (psc->inputstate == 6) {
                   1166:                /*
                   1167:                 * We have a complete packet.
                   1168:                 * Extract the pertinent details.
                   1169:                 */
                   1170:                psc->inputstate = 0;
1.14      mlelstv  1171:                if ((psc->packet[0] & 0xfc) == 0x84 &&
                   1172:                    (psc->packet[3] & 0xcc) == 0xc4) {
1.28      jakllsch 1173:                        /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */
1.14      mlelstv  1174:                        pms_synaptics_passthrough(psc);
1.3       scw      1175:                } else {
1.14      mlelstv  1176:                        pms_synaptics_parse(psc);
1.1       christos 1177:                }
                   1178:        }
1.3       scw      1179: }
1.1       christos 1180:
1.9       perry    1181: static inline int
1.3       scw      1182: synaptics_finger_detect(struct synaptics_softc *sc, struct synaptics_packet *sp,
                   1183:     int *palmp)
                   1184: {
                   1185:        int fingers;
                   1186:
                   1187:        /* Assume no palm */
                   1188:        *palmp = 0;
                   1189:
                   1190:        /*
                   1191:         * Apply some hysteresis when checking for a finger.
                   1192:         * When the finger is first applied, we ignore it until the
                   1193:         * pressure exceeds the 'high' threshold. The finger is considered
                   1194:         * removed only when pressure falls beneath the 'low' threshold.
                   1195:         */
                   1196:        if ((sc->prev_fingers == 0 && sp->sp_z > synaptics_finger_high) ||
                   1197:            (sc->prev_fingers != 0 && sp->sp_z > synaptics_finger_low))
                   1198:                fingers = 1;
                   1199:        else
                   1200:                fingers = 0;
                   1201:
                   1202:        /*
                   1203:         * If the pad can't do palm detection, skip the rest.
                   1204:         */
                   1205:        if (fingers == 0 || (sc->flags & SYN_FLAG_HAS_PALM_DETECT) == 0)
                   1206:                return (fingers);
                   1207:
                   1208:        /*
                   1209:         * Palm detection
                   1210:         */
                   1211:        if (sp->sp_z > SYNAPTICS_FINGER_FLAT &&
                   1212:            sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)
                   1213:                *palmp = 1;
                   1214:
                   1215:        if (sc->prev_fingers == 0 &&
                   1216:            (sp->sp_z > SYNAPTICS_FINGER_FLAT ||
                   1217:             sp->sp_w >= SYNAPTICS_WIDTH_PALM_MIN)) {
                   1218:                /*
                   1219:                 * Contact area or pressure is too great to be a finger.
                   1220:                 * Just ignore it for now.
                   1221:                 */
                   1222:                return (0);
                   1223:        }
                   1224:
                   1225:        /*
                   1226:         * Detect 2 and 3 fingers if supported, but only if multiple
                   1227:         * fingers appear within the tap gesture time period.
                   1228:         */
                   1229:        if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER &&
1.34      blymn    1230:            SYN_TIME(sc, sc->gesture_start_packet,
                   1231:            sp->sp_finger) < synaptics_gesture_length) {
1.3       scw      1232:                switch (sp->sp_w) {
                   1233:                case SYNAPTICS_WIDTH_TWO_FINGERS:
                   1234:                        fingers = 2;
                   1235:                        break;
                   1236:
                   1237:                case SYNAPTICS_WIDTH_THREE_OR_MORE:
                   1238:                        fingers = 3;
                   1239:                        break;
                   1240:
                   1241:                case SYNAPTICS_WIDTH_PEN:
                   1242:                        fingers = 1;
                   1243:                        break;
                   1244:
                   1245:                default:
                   1246:                        /*
                   1247:                         * The width value can report spurious single-finger
                   1248:                         * events after a multi-finger event.
                   1249:                         */
                   1250:                        if (sc->prev_fingers > 1)
                   1251:                                fingers = sc->prev_fingers;
                   1252:                        else
                   1253:                                fingers = 1;
                   1254:                        break;
1.1       christos 1255:                }
                   1256:        }
1.3       scw      1257:
                   1258:        return (fingers);
1.1       christos 1259: }
                   1260:
1.9       perry    1261: static inline void
1.3       scw      1262: synaptics_gesture_detect(struct synaptics_softc *sc,
                   1263:     struct synaptics_packet *sp, int fingers)
                   1264: {
1.32      christos 1265:        int gesture_len, gesture_buttons;
1.3       scw      1266:        int set_buttons;
                   1267:
1.34      blymn    1268:        gesture_len = SYN_TIME(sc, sc->gesture_start_packet, sp->sp_finger);
1.3       scw      1269:        gesture_buttons = sc->gesture_buttons;
1.1       christos 1270:
1.32      christos 1271:        if (fingers > 0 && (fingers == sc->prev_fingers)) {
                   1272:                /* Finger is still present */
                   1273:                sc->gesture_move_x = abs(sc->gesture_start_x - sp->sp_x);
                   1274:                sc->gesture_move_y = abs(sc->gesture_start_y - sp->sp_y);
                   1275:        } else
1.3       scw      1276:        if (fingers && sc->prev_fingers == 0) {
                   1277:                /*
                   1278:                 * Finger was just applied.
                   1279:                 * If the previous gesture was a single-click, set things
                   1280:                 * up to deal with a possible drag or double-click gesture.
                   1281:                 * Basically, if the finger is removed again within
                   1282:                 * 'synaptics_gesture_length' packets, this is treated
                   1283:                 * as a double-click. Otherwise we will emulate holding
                   1284:                 * the left button down whilst dragging the mouse.
                   1285:                 */
                   1286:                if (SYN_IS_SINGLE_TAP(sc->gesture_type))
                   1287:                        sc->gesture_type |= SYN_GESTURE_DRAG;
                   1288:
1.32      christos 1289:                sc->gesture_start_x = abs(sp->sp_x);
                   1290:                sc->gesture_start_y = abs(sp->sp_y);
                   1291:                sc->gesture_move_x = 0;
                   1292:                sc->gesture_move_y = 0;
1.34      blymn    1293:                sc->gesture_start_packet = sc->total_packets[0];
1.32      christos 1294:
                   1295: #ifdef DIAGNOSTIC
                   1296:                aprint_debug("Finger applied: gesture_start_x: %d gesture_start_y: %d\n",
                   1297:                        sc->gesture_start_x, sc->gesture_start_y);
                   1298: #endif
1.3       scw      1299:        } else
                   1300:        if (fingers == 0 && sc->prev_fingers != 0) {
                   1301:                /*
                   1302:                 * Finger was just removed.
                   1303:                 * Check if the contact time and finger movement were
                   1304:                 * small enough to qualify as a gesture.
                   1305:                 * Ignore finger movement if multiple fingers were
                   1306:                 * detected (the pad may report coordinates for any
                   1307:                 * of the fingers).
                   1308:                 */
1.32      christos 1309:
                   1310: #ifdef DIAGNOSTIC
                   1311:                aprint_debug("Finger removed: gesture_len: %d (%d)\n",
                   1312:                        gesture_len, synaptics_gesture_length);
                   1313:                aprint_debug("gesture_move_x: %d (%d) sp_x: %d\n",
                   1314:                        sc->gesture_move_x, synaptics_gesture_move, abs(sp->sp_x));
                   1315:                aprint_debug("gesture_move_y: %d (%d) sp_y: %d\n",
                   1316:                        sc->gesture_move_y, synaptics_gesture_move, abs(sp->sp_y));
                   1317: #endif
1.3       scw      1318:
                   1319:                if (gesture_len < synaptics_gesture_length &&
1.32      christos 1320:                    ((sc->gesture_move_x < synaptics_gesture_move &&
                   1321:                     sc->gesture_move_y < synaptics_gesture_move))) {
1.3       scw      1322:                        /*
                   1323:                         * Looking good so far.
                   1324:                         */
                   1325:                        if (SYN_IS_DRAG(sc->gesture_type)) {
                   1326:                                /*
                   1327:                                 * Promote this gesture to double-click.
                   1328:                                 */
                   1329:                                sc->gesture_type |= SYN_GESTURE_DOUBLE;
                   1330:                                sc->gesture_type &= ~SYN_GESTURE_SINGLE;
                   1331:                        } else {
                   1332:                                /*
                   1333:                                 * Single tap gesture. Set the tap length timer
                   1334:                                 * and flag a single-click.
                   1335:                                 */
1.34      blymn    1336:                                sc->gesture_tap_packet = sc->total_packets[0];
1.3       scw      1337:                                sc->gesture_type |= SYN_GESTURE_SINGLE;
                   1338:
                   1339:                                /*
                   1340:                                 * The gesture can be modified depending on
                   1341:                                 * the number of fingers detected.
                   1342:                                 *
                   1343:                                 * 1: Normal left button emulation.
                   1344:                                 * 2: Either middle button or right button
                   1345:                                 *    depending on the value of the two_fingers
                   1346:                                 *    sysctl variable.
                   1347:                                 * 3: Right button.
                   1348:                                 */
                   1349:                                switch (sc->prev_fingers) {
                   1350:                                case 2:
                   1351:                                        if (synaptics_two_fingers_emul == 1)
                   1352:                                                gesture_buttons |= PMS_RBUTMASK;
                   1353:                                        else
                   1354:                                        if (synaptics_two_fingers_emul == 2)
                   1355:                                                gesture_buttons |= PMS_MBUTMASK;
                   1356:                                        break;
                   1357:                                case 3:
                   1358:                                        gesture_buttons |= PMS_RBUTMASK;
                   1359:                                        break;
                   1360:                                default:
                   1361:                                        gesture_buttons |= PMS_LBUTMASK;
                   1362:                                        break;
                   1363:                                }
1.1       christos 1364:                        }
                   1365:                }
                   1366:
1.3       scw      1367:                /*
                   1368:                 * Always clear drag state when the finger is removed.
                   1369:                 */
                   1370:                sc->gesture_type &= ~SYN_GESTURE_DRAG;
                   1371:        }
                   1372:
                   1373:        if (sc->gesture_type == 0) {
                   1374:                /*
                   1375:                 * There is no gesture in progress.
                   1376:                 * Clear emulated button state.
                   1377:                 */
                   1378:                sc->gesture_buttons = 0;
                   1379:                return;
                   1380:        }
                   1381:
                   1382:        /*
                   1383:         * A gesture is in progress.
                   1384:         */
                   1385:        set_buttons = 0;
                   1386:
                   1387:        if (SYN_IS_SINGLE_TAP(sc->gesture_type)) {
                   1388:                /*
                   1389:                 * Single-click.
                   1390:                 * Activate the relevant button(s) until the
                   1391:                 * gesture tap timer has expired.
                   1392:                 */
1.34      blymn    1393:                if (SYN_TIME(sc, sc->gesture_tap_packet, sp->sp_finger) <
1.3       scw      1394:                    synaptics_gesture_length)
                   1395:                        set_buttons = 1;
                   1396:                else
                   1397:                        sc->gesture_type &= ~SYN_GESTURE_SINGLE;
                   1398:        } else
                   1399:        if (SYN_IS_DOUBLE_TAP(sc->gesture_type) && sc->prev_fingers == 0) {
                   1400:                /*
                   1401:                 * Double-click.
                   1402:                 * Activate the relevant button(s) once.
                   1403:                 */
                   1404:                set_buttons = 1;
                   1405:                sc->gesture_type &= ~SYN_GESTURE_DOUBLE;
                   1406:        }
                   1407:
                   1408:        if (set_buttons || SYN_IS_DRAG(sc->gesture_type)) {
                   1409:                /*
                   1410:                 * Single-click and drag.
                   1411:                 * Maintain button state until the finger is removed.
                   1412:                 */
                   1413:                sp->sp_left |= gesture_buttons & PMS_LBUTMASK;
                   1414:                sp->sp_right |= gesture_buttons & PMS_RBUTMASK;
                   1415:                sp->sp_middle |= gesture_buttons & PMS_MBUTMASK;
                   1416:        }
                   1417:
                   1418:        sc->gesture_buttons = gesture_buttons;
                   1419: }
                   1420:
1.9       perry    1421: static inline int
1.34      blymn    1422: synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history,
                   1423:                        int value)
1.3       scw      1424: {
                   1425:        int a, b, rv, count;
1.1       christos 1426:
1.34      blymn    1427:        count = sc->total_packets[finger];
1.3       scw      1428:
                   1429:        /*
                   1430:         * Once we've accumulated at least SYN_HIST_SIZE values, combine
                   1431:         * each new value with the previous two and return the average.
                   1432:         *
                   1433:         * This is necessary when the touchpad is operating in 80 packets
                   1434:         * per second mode, as it performs little internal filtering on
                   1435:         * reported values.
                   1436:         *
                   1437:         * Using a rolling average helps to filter out jitter caused by
                   1438:         * tiny finger movements.
                   1439:         */
1.34      blymn    1440:        if (sc->movement_history[finger] >= SYN_HIST_SIZE) {
1.3       scw      1441:                a = (history[(count + 0) % SYN_HIST_SIZE] +
                   1442:                    history[(count + 1) % SYN_HIST_SIZE]) / 2;
                   1443:
                   1444:                b = (value + history[(count + 0) % SYN_HIST_SIZE]) / 2;
                   1445:
                   1446:                rv = b - a;
                   1447:
                   1448:                /*
                   1449:                 * Don't report the movement if it's below a certain
                   1450:                 * threshold.
                   1451:                 */
                   1452:                if (abs(rv) < synaptics_movement_threshold)
                   1453:                        rv = 0;
                   1454:        } else
                   1455:                rv = 0;
                   1456:
                   1457:        /*
                   1458:         * Add the new value to the history buffer.
                   1459:         */
                   1460:        history[(count + 1) % SYN_HIST_SIZE] = value;
                   1461:
                   1462:        return (rv);
                   1463: }
                   1464:
                   1465: /* Edge detection */
                   1466: #define        SYN_EDGE_TOP            1
                   1467: #define        SYN_EDGE_BOTTOM         2
                   1468: #define        SYN_EDGE_LEFT           4
                   1469: #define        SYN_EDGE_RIGHT          8
                   1470:
1.9       perry    1471: static inline int
1.3       scw      1472: synaptics_check_edge(int x, int y)
                   1473: {
                   1474:        int rv = 0;
                   1475:
                   1476:        if (x < synaptics_edge_left)
                   1477:                rv |= SYN_EDGE_LEFT;
                   1478:        else
                   1479:        if (x > synaptics_edge_right)
                   1480:                rv |= SYN_EDGE_RIGHT;
                   1481:
                   1482:        if (y < synaptics_edge_bottom)
                   1483:                rv |= SYN_EDGE_BOTTOM;
                   1484:        else
                   1485:        if (y > synaptics_edge_top)
                   1486:                rv |= SYN_EDGE_TOP;
                   1487:
                   1488:        return (rv);
                   1489: }
                   1490:
1.9       perry    1491: static inline int
1.13      christos 1492: synaptics_edge_motion(struct synaptics_softc *sc, int delta, int dir)
1.3       scw      1493: {
                   1494:
                   1495:        /*
                   1496:         * When edge motion is enabled, synaptics_edge_motion_delta is
                   1497:         * combined with the current delta, together with the direction
                   1498:         * in which to simulate the motion. The result is added to
                   1499:         * the delta derived from finger movement. This provides a smooth
                   1500:         * transition from finger movement to edge motion.
                   1501:         */
                   1502:        delta = synaptics_edge_motion_delta + (dir * delta);
                   1503:        if (delta < 0)
                   1504:                return (0);
                   1505:        if (delta > synaptics_edge_motion_delta)
                   1506:                return (synaptics_edge_motion_delta);
                   1507:        return (delta);
                   1508: }
                   1509:
1.9       perry    1510: static inline int
1.3       scw      1511: synaptics_scale(int delta, int scale, int *remp)
                   1512: {
                   1513:        int rv;
                   1514:
                   1515:        /*
                   1516:         * Scale the raw delta in Synaptics coordinates (0-6143) into
                   1517:         * something more reasonable by dividing the raw delta by a
                   1518:         * scale factor. Any remainder from the previous scale result
                   1519:         * is added to the current delta before scaling.
                   1520:         * This prevents loss of resolution for very small/slow
                   1521:         * movements of the finger.
                   1522:         */
                   1523:        delta += *remp;
                   1524:        rv = delta / scale;
                   1525:        *remp = delta % scale;
                   1526:
                   1527:        return (rv);
                   1528: }
                   1529:
1.9       perry    1530: static inline void
1.3       scw      1531: synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp,
1.44      blymn    1532:     int finger, int scroll_emul, int *dxp, int *dyp, int *dzp)
1.3       scw      1533: {
1.44      blymn    1534:        int dx, dy, dz, edge;
                   1535:
                   1536:        dx = dy = dz = 0;
1.3       scw      1537:
                   1538:        /*
1.44      blymn    1539:         * Compute the next values of dx and dy and dz.  If scroll_emul
                   1540:         * is non-zero, take the dy and used it as use it as dz so we
                   1541:         * can emulate a scroll wheel.
1.3       scw      1542:         */
1.44      blymn    1543:        if (scroll_emul == 0) {
                   1544:                dx = synaptics_filter_policy(sc, finger, sc->history_x[finger],
                   1545:                        sp->sp_x);
                   1546:                dy = synaptics_filter_policy(sc, finger, sc->history_y[finger],
                   1547:                        sp->sp_y);
                   1548:        } else {
                   1549:                dz = synaptics_filter_policy(sc, finger, sc->history_z[finger],
                   1550:                        sp->sp_y);
                   1551:                dx = dy = 0;
                   1552:        }
1.3       scw      1553:
                   1554:        /*
                   1555:         * If we're dealing with a drag gesture, and the finger moves to
                   1556:         * the edge of the touchpad, apply edge motion emulation if it
                   1557:         * is enabled.
                   1558:         */
                   1559:        if (synaptics_edge_motion_delta && SYN_IS_DRAG(sc->gesture_type)) {
                   1560:                edge = synaptics_check_edge(sp->sp_x, sp->sp_y);
                   1561:
                   1562:                if (edge & SYN_EDGE_LEFT)
                   1563:                        dx -= synaptics_edge_motion(sc, dx, 1);
                   1564:                if (edge & SYN_EDGE_RIGHT)
                   1565:                        dx += synaptics_edge_motion(sc, dx, -1);
                   1566:                if (edge & SYN_EDGE_BOTTOM)
                   1567:                        dy -= synaptics_edge_motion(sc, dy, 1);
                   1568:                if (edge & SYN_EDGE_TOP)
                   1569:                        dy += synaptics_edge_motion(sc, dy, -1);
                   1570:        }
                   1571:
                   1572:        /*
1.44      blymn    1573:         * Apply scaling to the deltas
1.3       scw      1574:         */
1.34      blymn    1575:        dx = synaptics_scale(dx, synaptics_scale_x, &sc->rem_x[finger]);
                   1576:        dy = synaptics_scale(dy, synaptics_scale_y, &sc->rem_y[finger]);
1.44      blymn    1577:        dz = synaptics_scale(dz, synaptics_scale_z, &sc->rem_z[finger]);
1.1       christos 1578:
1.3       scw      1579:        /*
                   1580:         * Clamp deltas to specified maximums.
                   1581:         */
1.43      blymn    1582:        if (abs(dx) > synaptics_max_speed_x)
                   1583:                dx = ((dx >= 0)? 1 : -1) * synaptics_max_speed_x;
                   1584:        if (abs(dy) > synaptics_max_speed_y)
                   1585:                dy = ((dy >= 0)? 1 : -1) * synaptics_max_speed_y;
1.44      blymn    1586:        if (abs(dz) > synaptics_max_speed_z)
                   1587:                dz = ((dz >= 0)? 1 : -1) * synaptics_max_speed_z;
1.1       christos 1588:
1.3       scw      1589:        *dxp = dx;
                   1590:        *dyp = dy;
1.44      blymn    1591:        *dzp = dz;
1.1       christos 1592:
1.34      blymn    1593:        sc->movement_history[finger]++;
1.3       scw      1594: }
1.1       christos 1595:
1.3       scw      1596: static void
                   1597: pms_synaptics_process_packet(struct pms_softc *psc, struct synaptics_packet *sp)
                   1598: {
                   1599:        struct synaptics_softc *sc = &psc->u.synaptics;
                   1600:        int dx, dy, dz;
                   1601:        int fingers, palm, buttons, changed;
1.44      blymn    1602:        int s, z_emul;
1.1       christos 1603:
1.3       scw      1604:        /*
                   1605:         * Do Z-axis emulation using up/down buttons if required.
                   1606:         * Note that the pad will send a one second burst of packets
                   1607:         * when an up/down button is pressed and held. At the moment
                   1608:         * we don't deal with auto-repeat, so convert the burst into
                   1609:         * a one-shot.
                   1610:         */
                   1611:        dz = 0;
                   1612:        if (synaptics_up_down_emul == 2) {
                   1613:                if (sc->up_down == 0) {
                   1614:                        if (sp->sp_up && sp->sp_down) {
                   1615:                                /*
                   1616:                                 * Most up/down buttons will be actuated using
                   1617:                                 * a rocker switch, so we should never see
                   1618:                                 * them both simultaneously. But just in case,
                   1619:                                 * treat this situation as a middle button
                   1620:                                 * event.
                   1621:                                 */
                   1622:                                sp->sp_middle = 1;
                   1623:                        } else
                   1624:                        if (sp->sp_up)
                   1625:                                dz = -synaptics_up_down_motion_delta;
                   1626:                        else
                   1627:                        if (sp->sp_down)
                   1628:                                dz = synaptics_up_down_motion_delta;
1.1       christos 1629:                }
                   1630:
1.3       scw      1631:                sc->up_down = sp->sp_up | sp->sp_down;
                   1632:                sp->sp_up = sp->sp_down = 0;
                   1633:        }
                   1634:
                   1635:        /*
                   1636:         * Determine whether or not a finger is on the pad.
                   1637:         * On some pads, this will return the number of fingers
                   1638:         * detected.
                   1639:         */
                   1640:        fingers = synaptics_finger_detect(sc, sp, &palm);
                   1641:
                   1642:        /*
1.34      blymn    1643:         * Do gesture processing only if we didn't detect a palm and
                   1644:         * it is not the seondary finger.
1.3       scw      1645:         */
1.34      blymn    1646:        if ((sp->sp_finger == 0) && (palm == 0))
1.3       scw      1647:                synaptics_gesture_detect(sc, sp, fingers);
                   1648:        else
                   1649:                sc->gesture_type = sc->gesture_buttons = 0;
1.1       christos 1650:
1.3       scw      1651:        /*
                   1652:         * Determine what buttons to report
                   1653:         */
                   1654:        buttons = (sp->sp_left ? 0x1 : 0) |
                   1655:            (sp->sp_middle ? 0x2 : 0) |
                   1656:            (sp->sp_right ? 0x4 : 0) |
                   1657:            (sp->sp_up ? 0x8 : 0) |
                   1658:            (sp->sp_down ? 0x10 : 0);
1.14      mlelstv  1659:        changed = buttons ^ (psc->buttons & 0x1f);
                   1660:        psc->buttons ^= changed;
1.1       christos 1661:
1.3       scw      1662:        sc->prev_fingers = fingers;
1.34      blymn    1663:        sc->total_packets[sp->sp_finger]++;
1.1       christos 1664:
1.3       scw      1665:        /*
1.34      blymn    1666:         * Do movement processing IFF we have a single finger and no palm or
                   1667:         * a secondary finger and no palm.
1.3       scw      1668:         */
1.36      jmcneill 1669:        if (palm == 0 && synaptics_movement_enable) {
1.34      blymn    1670:                if (fingers == 1) {
1.44      blymn    1671:                        z_emul = 0;
                   1672:
                   1673:                        if ((sp->sp_w >= synaptics_fscroll_min) &&
                   1674:                            (sp->sp_w <= synaptics_fscroll_max)) {
                   1675:                                z_emul = 1;
                   1676:                                sc->dz_hold = synaptics_dz_hold;
                   1677:                        }
                   1678:
                   1679:                        if (sc->dz_hold > 0) {
                   1680:                                z_emul = 1;
                   1681:                        }
                   1682:
                   1683:                        synaptics_movement(sc, sp, sp->sp_finger,
                   1684:                                z_emul, &dx, &dy, &dz);
1.34      blymn    1685:                } else {
                   1686:                        /*
                   1687:                         * No valid finger. Therefore no movement.
                   1688:                         */
                   1689:                        sc->movement_history[sp->sp_finger] = 0;
                   1690:                        sc->rem_x[sp->sp_finger] = sc->rem_y[sp->sp_finger] = 0;
                   1691:                        dx = dy = 0;
                   1692:                }
                   1693:        } else {
1.3       scw      1694:                /*
                   1695:                 * No valid finger. Therefore no movement.
                   1696:                 */
1.34      blymn    1697:                sc->movement_history[0] = 0;
1.44      blymn    1698:                sc->rem_x[0] = sc->rem_y[0] = sc->rem_z[0] = 0;
                   1699:                dx = dy = dz = 0;
1.3       scw      1700:        }
1.1       christos 1701:
1.44      blymn    1702:        if (sc->dz_hold > 0)
                   1703:                sc->dz_hold--;
                   1704:
1.3       scw      1705:        /*
                   1706:         * Pass the final results up to wsmouse_input() if necessary.
                   1707:         */
                   1708:        if (dx || dy || dz || changed) {
1.14      mlelstv  1709:                buttons = (psc->buttons & 0x1f) | ((psc->buttons >> 5) & 0x7);
1.3       scw      1710:                s = spltty();
1.12      plunky   1711:                wsmouse_input(psc->sc_wsmousedev,
                   1712:                                buttons,
                   1713:                                dx, dy, dz, 0,
                   1714:                                WSMOUSE_INPUT_DELTA);
1.3       scw      1715:                splx(s);
1.1       christos 1716:        }
                   1717: }

CVSweb <webmaster@jp.NetBSD.org>