In article <20171024083449.ga...@internode.on.net>, Brett Lymn <bl...@internode.on.net> wrote: > >I have been going around in circles with this for a while trying to get >my clickpad initialised to work with extended w mode. I don't have it >right but I have noticed if I boot windows or fedora and then reboot to >netbsd I have extended_w. Doing this I have multi-finger working so you >can hold down a button and scroll though a menu with the other finger. >This patch also provides 3 button emulation for a click pad. There are >some sysctls that set the size of the mouse button regions (height and >left, middle and right button regions). I am putting this out there >just in case it works for others and the initialisation issue is just my >hardware. Even if extended_w does not work it does at least mean that >click pads will have 3 buttons and you can scroll a little bit by moving >the finger that has activated the button (I have been surviving like >this for quite some time). Any comments/improvements welcome....
Looks good, but let's merge all common command sets thusly (not even compile tested): Index: synaptics.c =================================================================== RCS file: /cvsroot/src/sys/dev/pckbport/synaptics.c,v retrieving revision 1.33 diff -u -u -r1.33 synaptics.c --- synaptics.c 4 Mar 2015 22:58:35 -0000 1.33 +++ synaptics.c 24 Oct 2017 18:47:57 -0000 @@ -80,6 +80,10 @@ 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_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_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,6 +141,48 @@ static int synaptics_max_speed_y_nodenum; static int synaptics_movement_threshold_nodenum; +static int +synaptics_poll_cmd(struct pmc_softc *psc, ...) +{ + u_char cmd[4]; + size_t i; + va_list ap; + + va_start(ap, psc); + + for (size_t 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]) +{ + u_char cmd[1] = { PMS_RESET }; + int 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 resp; +} + +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) { @@ -156,11 +208,7 @@ 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 +240,9 @@ 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 +313,7 @@ * 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, resp); } if (resp[1] != SYNAPTICS_MAGIC_BYTE) { @@ -293,12 +336,9 @@ 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 +425,7 @@ { struct pms_softc *psc = vsc; struct synaptics_softc *sc = &psc->u.synaptics; - u_char cmd[2], resp[2]; + u_char cmd[2], resp[3], enable_modes; int res; if (sc->flags & SYN_FLAG_HAS_PASSTHROUGH) { @@ -393,21 +433,43 @@ * 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, resp); } /* * 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 +477,18 @@ 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]); + u_char resp[2]; + (void)synaptics_poll_reset(vsc, resp); } static void @@ -655,6 +708,42 @@ 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 +805,16 @@ 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 +832,152 @@ { 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; + break; - /* 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; + break; + + default: + aprint_error_dev(psc->sc_dev, + "invalid extended w mode %d\n", + ew_mode); + return; + break; + } } 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. + */ + if (sp.sp_y < synaptics_button_boundary) { + if (sp.sp_x > synaptics_button3) { + sp.sp_right = + ((psc->packet[0] ^ psc->packet[3]) & 0x01) ? PMS_RBUTMASK : 0; + } else if (sp.sp_x > synaptics_button2) { + sp.sp_middle = + ((psc->packet[0] ^ psc->packet[3]) & 0x01) ? PMS_MBUTMASK : 0; + } else { + sp.sp_left = + ((psc->packet[0] ^ psc->packet[3]) & 0x01) ? PMS_LBUTMASK : 0; + } + } else + sp.sp_left = + ((psc->packet[0] ^ psc->packet[3]) & 0x01) ? 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 + /* 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; + + } pms_synaptics_process_packet(psc, &sp); } @@ -853,6 +1040,9 @@ "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 +1078,6 @@ * 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 +1137,8 @@ * 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 +1175,7 @@ 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 +1200,7 @@ 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 +1243,7 @@ * 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 +1300,7 @@ * 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 +1329,12 @@ } 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 +1347,7 @@ * 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 +1439,17 @@ 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 +1472,8 @@ /* * 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 +1486,7 @@ *dxp = dx; *dyp = dy; - sc->movement_history++; + sc->movement_history[finger]++; } static void @@ -1343,9 +1536,10 @@ 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 +1556,29 @@ 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; }