Index: linux/drivers/input/mouse/synaptics.h =================================================================== --- linux/drivers/input/mouse/synaptics.h (revision 5) +++ linux/drivers/input/mouse/synaptics.h (revision 10) @@ -37,6 +37,7 @@ /* synaptics capability bits */ #define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) +#define SYN_CAP_CLIENT(c) ((c) & (1 << 7)) #define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) #define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) #define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) @@ -57,7 +58,9 @@ #define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) #define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) +/* client commands*/ + struct synaptics_parameters { int left_edge; /* Edge coordinates, absolute */ int right_edge; @@ -71,6 +74,7 @@ int scroll_dist_vert; /* Scrolling distance in absolute coordinates */ int scroll_dist_horiz; /* Scrolling distance in absolute coordinates */ int speed; /* Pointer motion speed */ + int client_speed; /* Client Pointer motion speed */ int edge_motion_speed; /* Edge motion speed when dragging */ int updown_button_scrolling; /* Up/Down-Button scrolling or middle/double-click */ }; @@ -87,6 +91,7 @@ int right; int up; int down; + int client; }; #define SYNAPTICS_MOVE_HISTORY 5 Index: linux/drivers/input/mouse/synaptics.c =================================================================== --- linux/drivers/input/mouse/synaptics.c (revision 5) +++ linux/drivers/input/mouse/synaptics.c (revision 10) @@ -20,6 +20,9 @@ * Copyright (c) 1998-2000 Bruce Kalk * code for the special synaptics commands (from the tpconfig-source) * + * 2003 Arne Köwing + * Code for Synaptics client/passthrough (from gpm source) + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. @@ -62,6 +65,7 @@ return 0; } + /* * Send a command to the synpatics touchpad by special commands */ @@ -74,6 +78,85 @@ return 0; } +static int synaptics_client_sendbyte(struct psmouse *psmouse, unsigned char c) +{ + unsigned char param[4]; + synaptics_special_cmd(psmouse, c); + param[0]=40; + if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE)) + return -1; + return 0; +} + +static int synaptics_client_command(struct psmouse *psmouse, unsigned char *param, int command) +{ + int timeout = 500000; /* 500 msec */ + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int i; + + psmouse->cmdcnt = receive; + + if (command == PSMOUSE_CMD_RESET_BAT) + timeout = 2000000; /* 2 sec */ + + if (command & 0xff) + if (synaptics_client_sendbyte(psmouse, command & 0xff)) + return (psmouse->cmdcnt = 0) - 1; + + for (i = 0; i < send; i++) + if (synaptics_client_sendbyte(psmouse, param[i])) + return (psmouse->cmdcnt = 0) - 1; + + while (psmouse->cmdcnt && timeout--) { + + if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT) + timeout = 100000; + + if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID && + psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) { + psmouse->cmdcnt = 0; + break; + } + + udelay(1); + } + + for (i = 0; i < receive; i++) + param[i] = psmouse->cmdbuf[(receive - 1) - i]; + + if (psmouse->cmdcnt) + return (psmouse->cmdcnt = 0) - 1; + + return 0; +} + +/* +static int synaptics_client_special_cmd(struct psmouse *psmouse, unsigned char command) +{ + int i; + + if (synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + unsigned char d = (command >> i) & 3; + if (synaptics_client_command(psmouse,&d, PSMOUSE_CMD_SETRES)) + return -1; + } + return 0; +} +*/ +static int synaptics_client_reset(struct psmouse *psmouse) +{ + unsigned char param[2]; + if(synaptics_client_command(psmouse,param,PSMOUSE_CMD_RESET_BAT)) + return -1; + if (param[0] == 0xAA && param[1] == 0x00) + return 0; + return -1; +} + /***************************************************************************** * Synaptics communications functions ****************************************************************************/ @@ -104,6 +187,7 @@ return -1; } + /* * Read the model-id bytes from the touchpad * see also SYN_MODEL_* macros @@ -152,9 +236,17 @@ static int synaptics_enable_device(struct psmouse *psmouse) { - if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) - return -1; - return 0; + struct synaptics_data *priv = psmouse->private; + if (SYN_CAP_CLIENT(priv->capabilities)) + { + if(synaptics_client_reset(psmouse)) + return -1; + if(synaptics_client_command(psmouse,NULL,PSMOUSE_CMD_ENABLE)) + return -1; + } + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) + return -1; + return 0; } static void print_ident(struct synaptics_data *priv) @@ -181,6 +273,8 @@ printk(KERN_INFO " -> multifinger detection\n"); if (SYN_CAP_PALMDETECT(priv->capabilities)) printk(KERN_INFO " -> palm detection\n"); + if (SYN_CAP_CLIENT(priv->capabilities)) + printk(KERN_INFO " -> client detection\n"); } } @@ -240,6 +334,7 @@ .scroll_dist_vert = 100, .scroll_dist_horiz = 100, .speed = 25, + .client_speed = 200, .edge_motion_speed = 40, .updown_button_scrolling = 1 }; @@ -340,24 +435,43 @@ struct synaptics_hw_state *hw) { unsigned char *buf = priv->proto_buf; + hw->w = (((buf[0] & 0x30) >> 2) | + ((buf[0] & 0x04) >> 1) | + ((buf[3] & 0x04) >> 2)); + hw->client =0; + if (SYN_CAP_EXTENDED(priv->capabilities) && + (SYN_CAP_CLIENT(priv->capabilities))) { + if(hw->w == 0x03) + { + printk(KERN_DEBUG "SYN client pkg.\n"); + hw->client=1; + } + } + if (hw->client){ + if (buf[4]) + hw->x = (buf[1] & 0x10) ? buf[4]-256:buf[4]; + else + hw->x = 0; + if (buf[5]) + hw->y = -((buf[1] & 0x20) ? buf[5]-256:buf[5]); + else + hw->y = 0; + } - hw->x = (((buf[3] & 0x10) << 8) | + else { + hw->x = (((buf[3] & 0x10) << 8) | ((buf[1] & 0x0f) << 8) | buf[4]); - hw->y = (((buf[3] & 0x20) << 7) | + hw->y = (((buf[3] & 0x20) << 7) | ((buf[1] & 0xf0) << 4) | buf[5]); - + } hw->z = buf[2]; - hw->w = (((buf[0] & 0x30) >> 2) | - ((buf[0] & 0x04) >> 1) | - ((buf[3] & 0x04) >> 2)); - + hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x2) ? 1 : 0; hw->up = 0; hw->down = 0; - if (SYN_CAP_EXTENDED(priv->capabilities) && (SYN_CAP_FOUR_BUTTON(priv->capabilities))) { hw->up = ((buf[3] & 0x01)) ? 1 : 0; @@ -367,6 +481,7 @@ if (hw->right) hw->down = !hw->down; } + } static int synaptics_emulate_mid_button(struct synaptics_data *priv, @@ -494,6 +609,11 @@ edge = edge_detection(priv, hw.x, hw.y); + /* + * client-mouse handling + */ + + mid = synaptics_emulate_mid_button(priv, &hw); /* Up/Down-button scrolling or middle/double-click */ @@ -515,8 +635,11 @@ hw.up = hw.down = 0; } - finger = synaptics_detect_finger(priv, &hw); - + if(hw.client) + finger=0; + else + finger = synaptics_detect_finger(priv, &hw); + /* tap and drag detection */ if (priv->palm) { /* Palm detected, skip tap/drag processing */ @@ -601,7 +724,7 @@ } else { priv->tap = 0; } - + /* drag processing */ if (priv->drag) { hw.left |= priv->tap_left; @@ -663,9 +786,23 @@ } } + /* client movement */ + dx = dy = 0; + if (hw.client){ + dx=hw.x; + dy=hw.y; + priv->accum_dx += dx * para->client_speed ; + priv->accum_dy += dy * para->client_speed ; + + dx = priv->accum_dx / 256; + dy = priv->accum_dy / 256; + + priv->accum_dx -= dx * 256; + priv->accum_dy -= dy * 256; + } + /* movement */ - dx = dy = 0; - if (finger && !priv->vert_scroll_on && !priv->horiz_scroll_on && + if (finger&& !priv->vert_scroll_on && !priv->horiz_scroll_on && !priv->finger_count && !priv->palm) { if (priv->count_packet_finger > 3) { /* min. 3 packets */ int h2x = priv->move_hist[MOVE_HIST(2)].x; @@ -713,9 +850,10 @@ priv->finger_flag = finger; /* generate a history of the absolute positions */ - priv->move_hist[MOVE_HIST(0)].x = hw.x; - priv->move_hist[MOVE_HIST(0)].y = hw.y; - + if(!hw.client){ + priv->move_hist[MOVE_HIST(0)].x = hw.x; + priv->move_hist[MOVE_HIST(0)].y = hw.y; + } /* repeat timer for up/down buttons */ /* when you press a button the packets will only send for a second, so we have to use a timer for repeating */