Module Name: src Committed By: blymn Date: Mon Nov 6 21:07:17 UTC 2017
Modified Files: src/sys/dev/pckbport: synaptics.c synapticsreg.h synapticsvar.h Log Message: Add two finger support and middle/right button emulation. To generate a diff of this commit: cvs rdiff -u -r1.33 -r1.34 src/sys/dev/pckbport/synaptics.c cvs rdiff -u -r1.8 -r1.9 src/sys/dev/pckbport/synapticsreg.h cvs rdiff -u -r1.6 -r1.7 src/sys/dev/pckbport/synapticsvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pckbport/synaptics.c diff -u src/sys/dev/pckbport/synaptics.c:1.33 src/sys/dev/pckbport/synaptics.c:1.34 --- src/sys/dev/pckbport/synaptics.c:1.33 Wed Mar 4 22:58:35 2015 +++ src/sys/dev/pckbport/synaptics.c Mon Nov 6 21:07:17 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: synaptics.c,v 1.33 2015/03/04 22:58:35 christos Exp $ */ +/* $NetBSD: synaptics.c,v 1.34 2017/11/06 21:07:17 blymn Exp $ */ /* * Copyright (c) 2005, Steve C. Woodford @@ -48,7 +48,7 @@ #include "opt_pms.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.33 2015/03/04 22:58:35 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: synaptics.c,v 1.34 2017/11/06 21:07:17 blymn Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -80,6 +80,10 @@ struct synaptics_packet { signed short sp_y; u_char sp_z; /* Z (pressure) */ u_char sp_w; /* W (contact patch width) */ + signed short sp_sx; /* Secondary finger unscaled absolute */ + /* X/Y coordinates */ + signed short sp_xy; + u_char sp_finger; /* 0 for primary, 1 for secondary */ char sp_left; /* Left mouse button status */ char sp_right; /* Right mouse button status */ char sp_middle; /* Middle button status (possibly emulated) */ @@ -105,6 +109,9 @@ static int synaptics_edge_bottom = SYNAP static int synaptics_edge_motion_delta = 32; static u_int synaptics_finger_high = SYNAPTICS_FINGER_LIGHT + 5; static u_int synaptics_finger_low = SYNAPTICS_FINGER_LIGHT - 10; +static int synaptics_button_boundary = SYNAPTICS_EDGE_BOTTOM + 720; +static int synaptics_button2 = SYNAPTICS_EDGE_LEFT + (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; +static int synaptics_button3 = SYNAPTICS_EDGE_LEFT + 2 * (SYNAPTICS_EDGE_RIGHT - SYNAPTICS_EDGE_LEFT) / 3; static int synaptics_two_fingers_emul = 0; static int synaptics_scale_x = 16; static int synaptics_scale_y = 16; @@ -113,6 +120,9 @@ static int synaptics_max_speed_y = 32; static int synaptics_movement_threshold = 4; /* Sysctl nodes. */ +static int synaptics_button_boundary_nodenum; +static int synaptics_button2_nodenum; +static int synaptics_button3_nodenum; static int synaptics_up_down_emul_nodenum; static int synaptics_up_down_motion_delta_nodenum; static int synaptics_gesture_move_nodenum; @@ -131,11 +141,56 @@ static int synaptics_max_speed_x_nodenum static int synaptics_max_speed_y_nodenum; static int synaptics_movement_threshold_nodenum; +static int +synaptics_poll_cmd(struct pms_softc *psc, ...) +{ + u_char cmd[4]; + size_t i; + va_list ap; + + va_start(ap, psc); + + for (i = 0; i < __arraycount(cmd); i++) + if ((cmd[i] = (u_char)va_arg(ap, int)) == 0) + break; + va_end(ap); + + int res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, i, 0, + NULL, 0); + if (res) + aprint_error_dev(psc->sc_dev, "command error %#x\n", cmd[0]); + return res; +} + +static int +synaptics_poll_reset(struct pms_softc *psc) +{ + u_char resp[2]; + int res; + + u_char cmd[1] = { PMS_RESET }; + res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2, + resp, 1); + aprint_debug_dev(psc->sc_dev, "reset %d 0x%02x 0x%02x\n", + res, resp[0], resp[1]); + return res; +} + +static int +synaptics_poll_status(struct pms_softc *psc, u_char slice, u_char resp[3]) +{ + u_char cmd[1] = { PMS_SEND_DEV_STATUS }; + int res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, slice); + + return res | pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, + cmd, 1, 3, resp, 0); +} + static void pms_synaptics_probe_extended(struct pms_softc *psc) { struct synaptics_softc *sc = &psc->u.synaptics; - u_char cmd[1], resp[3]; + u_char resp[3]; int res; aprint_debug_dev(psc->sc_dev, @@ -156,11 +211,7 @@ pms_synaptics_probe_extended(struct pms_ if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >= SYNAPTICS_EXTENDED_QUERY) { - res = pms_sliced_command(psc->sc_kbctag, - psc->sc_kbcslot, SYNAPTICS_EXTENDED_QUERY); - cmd[0] = PMS_SEND_DEV_STATUS; - res |= pckbport_poll_cmd(psc->sc_kbctag, - psc->sc_kbcslot, cmd, 1, 3, resp, 0); + res = synaptics_poll_status(psc, SYNAPTICS_EXTENDED_QUERY, resp); if (res == 0) { int buttons = (resp[1] >> 4); aprint_debug_dev(psc->sc_dev, @@ -192,11 +243,9 @@ pms_synaptics_probe_extended(struct pms_ if (((sc->caps & SYNAPTICS_CAP_EXTNUM) + 0x08) >= SYNAPTICS_CONTINUED_CAPABILITIES) { - res = pms_sliced_command(psc->sc_kbctag, - psc->sc_kbcslot, SYNAPTICS_CONTINUED_CAPABILITIES); - cmd[0] = PMS_SEND_DEV_STATUS; - res |= pckbport_poll_cmd(psc->sc_kbctag, - psc->sc_kbcslot, cmd, 1, 3, resp, 0); + res = synaptics_poll_status(psc, + SYNAPTICS_CONTINUED_CAPABILITIES, resp); + /* * The following describes response for the * SYNAPTICS_CONTINUED_CAPABILITIES query. @@ -267,10 +316,7 @@ pms_synaptics_probe_init(void *vsc) * Reset device in case the probe confused it. */ doreset: - cmd[0] = PMS_RESET; - (void) pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, - 1, 2, resp, 1); - return (res); + return synaptics_poll_reset(psc); } if (resp[1] != SYNAPTICS_MAGIC_BYTE) { @@ -293,12 +339,9 @@ pms_synaptics_probe_init(void *vsc) goto done; } + /* Query the hardware capabilities. */ - res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, - SYNAPTICS_READ_CAPABILITIES); - cmd[0] = PMS_SEND_DEV_STATUS; - res |= pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 3, - resp, 0); + res = synaptics_poll_status(psc, SYNAPTICS_READ_CAPABILITIES, resp); if (res) { /* Hmm, failed to get capabilites. */ aprint_error_dev(psc->sc_dev, @@ -385,7 +428,7 @@ pms_synaptics_enable(void *vsc) { struct pms_softc *psc = vsc; struct synaptics_softc *sc = &psc->u.synaptics; - u_char cmd[2], resp[2]; + u_char enable_modes; int res; if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) { @@ -393,21 +436,43 @@ pms_synaptics_enable(void *vsc) * Extended capability probes can confuse the passthrough device; * reset the touchpad now to cure that. */ - cmd[0] = PMS_RESET; - res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, - 1, 2, resp, 1); + res = synaptics_poll_reset(psc); } /* * Enable Absolute mode with W (width) reporting, and set - * the packet rate to maximum (80 packets per second). + * the packet rate to maximum (80 packets per second). Enable + * extended W mode if supported so we can report second finger + * position. */ + enable_modes = + SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE; + + if (sc->flags & SYN_FLAG_HAS_EXTENDED_WMODE) + enable_modes |= SYNAPTICS_MODE_EXTENDED_W; + + /* + * Synaptics documentation says to disable device before + * setting mode. + */ + synaptics_poll_cmd(psc, PMS_DEV_DISABLE, 0); + /* a couple of set scales to clear out pending commands */ + for (int i = 0; i < 2; i++) + synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); + res = pms_sliced_command(psc->sc_kbctag, psc->sc_kbcslot, - SYNAPTICS_MODE_ABSOLUTE | SYNAPTICS_MODE_W | SYNAPTICS_MODE_RATE); - cmd[0] = PMS_SET_SAMPLE; - cmd[1] = SYNAPTICS_CMD_SET_MODE2; - res |= pckbport_enqueue_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 2, 0, - 1, NULL); + enable_modes); + if (res) + aprint_error("synaptics: set mode error\n"); + + synaptics_poll_cmd(psc, PMS_SET_SAMPLE, SYNAPTICS_CMD_SET_MODE2, 0); + + /* a couple of set scales to clear out pending commands */ + for (int i = 0; i < 2; i++) + synaptics_poll_cmd(psc, PMS_SET_SCALE11, 0); + + synaptics_poll_cmd(psc, PMS_DEV_ENABLE, 0); + sc->up_down = 0; sc->prev_fingers = 0; sc->gesture_start_x = sc->gesture_start_y = 0; @@ -415,27 +480,17 @@ pms_synaptics_enable(void *vsc) sc->gesture_tap_packet = 0; sc->gesture_type = 0; sc->gesture_buttons = 0; - sc->rem_x = sc->rem_y = 0; - sc->movement_history = 0; - if (res) { - aprint_error_dev(psc->sc_dev, - "synaptics_enable: Error enabling device.\n"); - } + sc->rem_x[0] = sc->rem_y[0] = 0; + sc->rem_x[1] = sc->rem_y[1] = 0; + sc->movement_history[0] = 0; + sc->movement_history[1] = 0; + sc->button_history = 0; } void pms_synaptics_resume(void *vsc) { - struct pms_softc *psc = vsc; - unsigned char cmd[1],resp[2] = { 0,0 }; - int res; - - cmd[0] = PMS_RESET; - res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, cmd, 1, 2, - resp, 1); - aprint_debug_dev(psc->sc_dev, - "pms_synaptics_resume: reset on resume %d 0x%02x 0x%02x\n", - res, resp[0], resp[1]); + (void)synaptics_poll_reset(vsc); } static void @@ -655,6 +710,42 @@ pms_sysctl_synaptics(struct sysctllog ** goto err; synaptics_movement_threshold_nodenum = node->sysctl_num; + + if ((rc = sysctl_createv(clog, 0, NULL, &node, + CTLFLAG_PERMANENT | CTLFLAG_READWRITE, + CTLTYPE_INT, "button_boundary", + SYSCTL_DESCR("Top edge of button area"), + pms_sysctl_synaptics_verify, 0, + &synaptics_button_boundary, + 0, CTL_HW, root_num, CTL_CREATE, + CTL_EOL)) != 0) + goto err; + + synaptics_button_boundary_nodenum = node->sysctl_num; + + if ((rc = sysctl_createv(clog, 0, NULL, &node, + CTLFLAG_PERMANENT | CTLFLAG_READWRITE, + CTLTYPE_INT, "button2_edge", + SYSCTL_DESCR("Left edge of button 2 region"), + pms_sysctl_synaptics_verify, 0, + &synaptics_button2, + 0, CTL_HW, root_num, CTL_CREATE, + CTL_EOL)) != 0) + goto err; + + synaptics_button2_nodenum = node->sysctl_num; + + if ((rc = sysctl_createv(clog, 0, NULL, &node, + CTLFLAG_PERMANENT | CTLFLAG_READWRITE, + CTLTYPE_INT, "button3_edge", + SYSCTL_DESCR("Left edge of button 3 region"), + pms_sysctl_synaptics_verify, 0, + &synaptics_button3, + 0, CTL_HW, root_num, CTL_CREATE, + CTL_EOL)) != 0) + goto err; + + synaptics_button3_nodenum = node->sysctl_num; return; err: @@ -716,6 +807,16 @@ pms_sysctl_synaptics_verify(SYSCTLFN_ARG if (t < 0 || t > (SYNAPTICS_EDGE_MAX / 4)) return (EINVAL); } else + if (node.sysctl_num == synaptics_button_boundary) { + if (t < 0 || t < SYNAPTICS_EDGE_BOTTOM || + t > SYNAPTICS_EDGE_TOP) + return (EINVAL); + } else + if (node.sysctl_num == synaptics_button2 || + node.sysctl_num == synaptics_button3) { + if (t < SYNAPTICS_EDGE_LEFT || t > SYNAPTICS_EDGE_RIGHT) + return (EINVAL); + } else return (EINVAL); *(int *)rnode->sysctl_data = t; @@ -733,64 +834,145 @@ pms_synaptics_parse(struct pms_softc *ps { struct synaptics_softc *sc = &psc->u.synaptics; struct synaptics_packet sp; + char new_buttons, ew_mode; memset(&sp, 0, sizeof(sp)); - /* Absolute X/Y coordinates of finger */ - sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) + - ((psc->packet[3] & 0x10) << 8); - sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) + - ((psc->packet[3] & 0x20) << 7); - - /* Pressure */ - sp.sp_z = psc->packet[2]; - /* Width of finger */ sp.sp_w = ((psc->packet[0] & 0x30) >> 2) + ((psc->packet[0] & 0x04) >> 1) + ((psc->packet[3] & 0x04) >> 2); + sp.sp_finger = 0; + if (sp.sp_w == SYNAPTICS_WIDTH_EXTENDED_W) { + ew_mode = psc->packet[5] >> 4; + switch (ew_mode) + { + case SYNAPTICS_EW_WHEEL: + /* scroll wheel report, ignore for now */ + aprint_debug_dev(psc->sc_dev, "mouse wheel packet\n"); + return; - /* Left/Right button handling. */ - sp.sp_left = psc->packet[0] & PMS_LBUTMASK; - sp.sp_right = psc->packet[0] & PMS_RBUTMASK; - - /* Up/Down buttons. */ - if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) { - /* Old up/down buttons. */ - sp.sp_up = sp.sp_left ^ - (psc->packet[3] & PMS_LBUTMASK); - sp.sp_down = sp.sp_right ^ - (psc->packet[3] & PMS_RBUTMASK); - } else - if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS && - ((psc->packet[0] & PMS_RBUTMASK) ^ - (psc->packet[3] & PMS_RBUTMASK))) { - /* New up/down button. */ - sp.sp_up = psc->packet[4] & SYN_1BUTMASK; - sp.sp_down = psc->packet[5] & SYN_2BUTMASK; + case SYNAPTICS_EW_SECONDARY_FINGER: + /* parse the second finger report */ + + sp.sp_finger = 1; /* just one other finger for now */ + sp.sp_x = psc->packet[1] + + ((psc->packet[4] & 0x0f) << 8); + sp.sp_y = psc->packet[2] + + ((psc->packet[4] & 0xf0) << 4); + sp.sp_z = (psc->packet[3] & 0x30) + + (psc->packet[5] & 0x0f); + + /* keep same buttons down as primary */ + sp.sp_left = sc->button_history & PMS_LBUTMASK; + sp.sp_middle = sc->button_history & PMS_MBUTMASK; + sp.sp_right = sc->button_history & PMS_RBUTMASK; + break; + + case SYNAPTICS_EW_FINGER_STATUS: + /* reports which finger is primary/secondary + * ignore for now. + */ + return; + + default: + aprint_error_dev(psc->sc_dev, + "invalid extended w mode %d\n", + ew_mode); + return; + } } else { - sp.sp_up = 0; - sp.sp_down = 0; - } - if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) { - /* This is not correctly specified. Read this button press - * from L/U bit. - */ - sp.sp_left = ((psc->packet[0] ^ psc->packet[3]) & 0x01) ? 1 : 0; - } else - /* Middle button. */ - if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) { - /* Old style Middle Button. */ - sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^ - (psc->packet[3] & PMS_LBUTMASK); - } else - if (synaptics_up_down_emul == 1) { - /* Do middle button emulation using up/down buttons */ - sp.sp_middle = sp.sp_up | sp.sp_down; - sp.sp_up = sp.sp_down = 0; - } else - sp.sp_middle = 0; + /* Absolute X/Y coordinates of finger */ + sp.sp_x = psc->packet[4] + ((psc->packet[1] & 0x0f) << 8) + + ((psc->packet[3] & 0x10) << 8); + sp.sp_y = psc->packet[5] + ((psc->packet[1] & 0xf0) << 4) + + ((psc->packet[3] & 0x20) << 7); + + /* Pressure */ + sp.sp_z = psc->packet[2]; + + /* Left/Right button handling. */ + sp.sp_left = psc->packet[0] & PMS_LBUTMASK; + sp.sp_right = psc->packet[0] & PMS_RBUTMASK; + + /* Up/Down buttons. */ + if (sc->flags & SYN_FLAG_HAS_BUTTONS_4_5) { + /* Old up/down buttons. */ + sp.sp_up = sp.sp_left ^ + (psc->packet[3] & PMS_LBUTMASK); + sp.sp_down = sp.sp_right ^ + (psc->packet[3] & PMS_RBUTMASK); + } else if (sc->flags & SYN_FLAG_HAS_UP_DOWN_BUTTONS && + ((psc->packet[0] & PMS_RBUTMASK) ^ + (psc->packet[3] & PMS_RBUTMASK))) { + /* New up/down button. */ + sp.sp_up = psc->packet[4] & SYN_1BUTMASK; + sp.sp_down = psc->packet[5] & SYN_2BUTMASK; + } else { + sp.sp_up = 0; + sp.sp_down = 0; + } + + new_buttons = 0; + if(sc->flags & SYN_FLAG_HAS_ONE_BUTTON_CLICKPAD) { + /* This is not correctly specified. Read this button press + * from L/U bit. Emulate 3 buttons by checking the + * coordinates of the click and returning the appropriate + * button code. Outside the button region default to a + * left click. + */ + u_char bstate = (psc->packet[0] ^ psc->packet[3]) + & 0x01; + if (sp.sp_y < synaptics_button_boundary) { + if (sp.sp_x > synaptics_button3) { + sp.sp_right = + bstate ? PMS_RBUTMASK : 0; + } else if (sp.sp_x > synaptics_button2) { + sp.sp_middle = + bstate ? PMS_MBUTMASK : 0; + } else { + sp.sp_left = bstate ? PMS_LBUTMASK : 0; + } + } else + sp.sp_left = bstate ? 1 : 0; + new_buttons = sp.sp_left | sp.sp_middle | sp.sp_right; + if (new_buttons != sc->button_history) { + if (sc->button_history == 0) + sc->button_history = new_buttons; + else if (new_buttons == 0) { + sc->button_history = 0; + /* ensure all buttons are cleared just in + * case finger comes off in a different + * region. + */ + sp.sp_left = 0; + sp.sp_middle = 0; + sp.sp_right = 0; + } else { + /* make sure we keep the same button even + * if the finger moves to a different + * region. This precludes chording + * but, oh well. + */ + sp.sp_left = sc->button_history & PMS_LBUTMASK; + sp.sp_middle = sc->button_history + & PMS_MBUTMASK; + sp.sp_right = sc->button_history & PMS_RBUTMASK; + } + } + } else if (sc->flags & SYN_FLAG_HAS_MIDDLE_BUTTON) { + /* Old style Middle Button. */ + sp.sp_middle = (psc->packet[0] & PMS_LBUTMASK) ^ + (psc->packet[3] & PMS_LBUTMASK); + } else if (synaptics_up_down_emul == 1) { + /* Do middle button emulation using up/down buttons */ + sp.sp_middle = sp.sp_up | sp.sp_down; + sp.sp_up = sp.sp_down = 0; + } else + sp.sp_middle = 0; + + } pms_synaptics_process_packet(psc, &sp); } @@ -853,6 +1035,9 @@ pms_synaptics_input(void *vsc, int data) "pms_input: unusual delay (%ld.%06ld s), " "scheduling reset\n", (long)diff.tv_sec, (long)diff.tv_usec); + printf("pms_input: unusual delay (%ld.%06ld s), " + "scheduling reset\n", + (long)diff.tv_sec, (long)diff.tv_usec); psc->inputstate = 0; psc->sc_enabled = 0; wakeup(&psc->sc_enabled); @@ -888,7 +1073,6 @@ pms_synaptics_input(void *vsc, int data) * Extract the pertinent details. */ psc->inputstate = 0; - if ((psc->packet[0] & 0xfc) == 0x84 && (psc->packet[3] & 0xcc) == 0xc4) { /* W = SYNAPTICS_WIDTH_PASSTHROUGH, PS/2 passthrough */ @@ -948,7 +1132,8 @@ synaptics_finger_detect(struct synaptics * fingers appear within the tap gesture time period. */ if (sc->flags & SYN_FLAG_HAS_MULTI_FINGER && - SYN_TIME(sc, sc->gesture_start_packet) < synaptics_gesture_length) { + SYN_TIME(sc, sc->gesture_start_packet, + sp->sp_finger) < synaptics_gesture_length) { switch (sp->sp_w) { case SYNAPTICS_WIDTH_TWO_FINGERS: fingers = 2; @@ -985,7 +1170,7 @@ synaptics_gesture_detect(struct synaptic int gesture_len, gesture_buttons; int set_buttons; - gesture_len = SYN_TIME(sc, sc->gesture_start_packet); + gesture_len = SYN_TIME(sc, sc->gesture_start_packet, sp->sp_finger); gesture_buttons = sc->gesture_buttons; if (fingers > 0 && (fingers == sc->prev_fingers)) { @@ -1010,7 +1195,7 @@ synaptics_gesture_detect(struct synaptic sc->gesture_start_y = abs(sp->sp_y); sc->gesture_move_x = 0; sc->gesture_move_y = 0; - sc->gesture_start_packet = sc->total_packets; + sc->gesture_start_packet = sc->total_packets[0]; #ifdef DIAGNOSTIC aprint_debug("Finger applied: gesture_start_x: %d gesture_start_y: %d\n", @@ -1053,7 +1238,7 @@ synaptics_gesture_detect(struct synaptic * Single tap gesture. Set the tap length timer * and flag a single-click. */ - sc->gesture_tap_packet = sc->total_packets; + sc->gesture_tap_packet = sc->total_packets[0]; sc->gesture_type |= SYN_GESTURE_SINGLE; /* @@ -1110,7 +1295,7 @@ synaptics_gesture_detect(struct synaptic * Activate the relevant button(s) until the * gesture tap timer has expired. */ - if (SYN_TIME(sc, sc->gesture_tap_packet) < + if (SYN_TIME(sc, sc->gesture_tap_packet, sp->sp_finger) < synaptics_gesture_length) set_buttons = 1; else @@ -1139,11 +1324,12 @@ synaptics_gesture_detect(struct synaptic } static inline int -synaptics_filter_policy(struct synaptics_softc *sc, int *history, int value) +synaptics_filter_policy(struct synaptics_softc *sc, int finger, int *history, + int value) { int a, b, rv, count; - count = sc->total_packets; + count = sc->total_packets[finger]; /* * Once we've accumulated at least SYN_HIST_SIZE values, combine @@ -1156,7 +1342,7 @@ synaptics_filter_policy(struct synaptics * Using a rolling average helps to filter out jitter caused by * tiny finger movements. */ - if (sc->movement_history >= SYN_HIST_SIZE) { + if (sc->movement_history[finger] >= SYN_HIST_SIZE) { a = (history[(count + 0) % SYN_HIST_SIZE] + history[(count + 1) % SYN_HIST_SIZE]) / 2; @@ -1248,15 +1434,17 @@ synaptics_scale(int delta, int scale, in static inline void synaptics_movement(struct synaptics_softc *sc, struct synaptics_packet *sp, - int *dxp, int *dyp) + int finger, int *dxp, int *dyp) { int dx, dy, edge; /* * Compute the next values of dx and dy */ - dx = synaptics_filter_policy(sc, sc->history_x, sp->sp_x); - dy = synaptics_filter_policy(sc, sc->history_y, sp->sp_y); + dx = synaptics_filter_policy(sc, finger, sc->history_x[finger], + sp->sp_x); + dy = synaptics_filter_policy(sc, finger, sc->history_y[finger], + sp->sp_y); /* * If we're dealing with a drag gesture, and the finger moves to @@ -1279,8 +1467,8 @@ synaptics_movement(struct synaptics_soft /* * Apply scaling to both deltas */ - dx = synaptics_scale(dx, synaptics_scale_x, &sc->rem_x); - dy = synaptics_scale(dy, synaptics_scale_y, &sc->rem_y); + dx = synaptics_scale(dx, synaptics_scale_x, &sc->rem_x[finger]); + dy = synaptics_scale(dy, synaptics_scale_y, &sc->rem_y[finger]); /* * Clamp deltas to specified maximums. @@ -1293,7 +1481,7 @@ synaptics_movement(struct synaptics_soft *dxp = dx; *dyp = dy; - sc->movement_history++; + sc->movement_history[finger]++; } static void @@ -1343,9 +1531,10 @@ pms_synaptics_process_packet(struct pms_ fingers = synaptics_finger_detect(sc, sp, &palm); /* - * Do gesture processing only if we didn't detect a palm. + * Do gesture processing only if we didn't detect a palm and + * it is not the seondary finger. */ - if (palm == 0) + if ((sp->sp_finger == 0) && (palm == 0)) synaptics_gesture_detect(sc, sp, fingers); else sc->gesture_type = sc->gesture_buttons = 0; @@ -1362,19 +1551,29 @@ pms_synaptics_process_packet(struct pms_ psc->buttons ^= changed; sc->prev_fingers = fingers; - sc->total_packets++; + sc->total_packets[sp->sp_finger]++; /* - * Do movement processing IFF we have a single finger and no palm. + * Do movement processing IFF we have a single finger and no palm or + * a secondary finger and no palm. */ - if (fingers == 1 && palm == 0) - synaptics_movement(sc, sp, &dx, &dy); - else { + if (palm == 0) { + if (fingers == 1) { + synaptics_movement(sc, sp, sp->sp_finger, &dx, &dy); + } else { + /* + * No valid finger. Therefore no movement. + */ + sc->movement_history[sp->sp_finger] = 0; + sc->rem_x[sp->sp_finger] = sc->rem_y[sp->sp_finger] = 0; + dx = dy = 0; + } + } else { /* * No valid finger. Therefore no movement. */ - sc->movement_history = 0; - sc->rem_x = sc->rem_y = 0; + sc->movement_history[0] = 0; + sc->rem_x[0] = sc->rem_y[0] = 0; dx = dy = 0; } Index: src/sys/dev/pckbport/synapticsreg.h diff -u src/sys/dev/pckbport/synapticsreg.h:1.8 src/sys/dev/pckbport/synapticsreg.h:1.9 --- src/sys/dev/pckbport/synapticsreg.h:1.8 Fri May 23 01:11:29 2014 +++ src/sys/dev/pckbport/synapticsreg.h Mon Nov 6 21:07:17 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: synapticsreg.h,v 1.8 2014/05/23 01:11:29 christos Exp $ */ +/* $NetBSD: synapticsreg.h,v 1.9 2017/11/06 21:07:17 blymn Exp $ */ /* * Copyright (c) 2005, Steve C. Woodford @@ -69,6 +69,7 @@ #define SYNAPTICS_MODE_ABSOLUTE (1 << 7) #define SYNAPTICS_MODE_RATE (1 << 6) #define SYNAPTICS_MODE_SLEEP (1 << 3) +#define SYNAPTICS_MODE_EXTENDED_W (1 << 2) /* double meaning */ #define SYNAPTICS_MODE_GEST (1 << 2) #define SYNAPTICS_MODE_4BYTE_CLIENT (1 << 1) #define SYNAPTICS_MODE_W (1) @@ -97,6 +98,7 @@ #define SYNAPTICS_WIDTH_TWO_FINGERS 0 #define SYNAPTICS_WIDTH_THREE_OR_MORE 1 #define SYNAPTICS_WIDTH_PEN 2 +#define SYNAPTICS_WIDTH_EXTENDED_W 2 #define SYNAPTICS_WIDTH_ADVANCEDGESTURE 2 #define SYNAPTICS_WIDTH_PASSTHROUGH 3 #define SYNAPTICS_WIDTH_FINGER_MIN 4 @@ -106,4 +108,9 @@ #define SYNAPTICS_WIDTH_PALM_MAX 14 #define SYNAPTICS_WIDTH_MAX 15 +/* Extended W types */ +#define SYNAPTICS_EW_WHEEL 0 +#define SYNAPTICS_EW_SECONDARY_FINGER 1 +#define SYNAPTICS_EW_FINGER_STATUS 2 + #endif /* _DEV_PCKBCPORT_SYNAPTICSREG_H_ */ Index: src/sys/dev/pckbport/synapticsvar.h diff -u src/sys/dev/pckbport/synapticsvar.h:1.6 src/sys/dev/pckbport/synapticsvar.h:1.7 --- src/sys/dev/pckbport/synapticsvar.h:1.6 Fri May 23 01:11:29 2014 +++ src/sys/dev/pckbport/synapticsvar.h Mon Nov 6 21:07:17 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: synapticsvar.h,v 1.6 2014/05/23 01:11:29 christos Exp $ */ +/* $NetBSD: synapticsvar.h,v 1.7 2017/11/06 21:07:17 blymn Exp $ */ /* * Copyright (c) 2005, Steve C. Woodford @@ -55,10 +55,10 @@ struct synaptics_softc { #define SYN_FLAG_HAS_TWO_BUTTON_CLICKPAD (1 << 10) #define SYN_FLAG_HAS_EXTENDED_WMODE (1 << 11) - u_int total_packets; /* Total number of packets received */ -#define SYN_TIME(sc,c) (((sc)->total_packets >= (c)) ? \ - ((sc)->total_packets - (c)) : \ - ((c) - (sc)->total_packets)) + u_int total_packets[2]; /* Total number of packets received */ +#define SYN_TIME(sc,c,n) (((sc)->total_packets[(n)] >= (c)) ? \ + ((sc)->total_packets[(n)] - (c)) : \ + ((c) - (sc)->total_packets[(n)])) int up_down; int prev_fingers; @@ -78,9 +78,10 @@ struct synaptics_softc { #define SYN_IS_DRAG(t) ((t) & SYN_GESTURE_DRAG) #define SYN_HIST_SIZE 4 - int rem_x, rem_y; - u_int movement_history; - int history_x[SYN_HIST_SIZE], history_y[SYN_HIST_SIZE]; + char button_history; + int rem_x[2], rem_y[2]; + u_int movement_history[2]; + int history_x[2][SYN_HIST_SIZE], history_y[2][SYN_HIST_SIZE]; }; int pms_synaptics_probe_init(void *vsc);