diff options
Diffstat (limited to 'drivers/input/mouse')
| -rw-r--r-- | drivers/input/mouse/Kconfig | 4 | ||||
| -rw-r--r-- | drivers/input/mouse/alps.c | 422 | ||||
| -rw-r--r-- | drivers/input/mouse/alps.h | 8 | ||||
| -rw-r--r-- | drivers/input/mouse/appletouch.c | 144 | ||||
| -rw-r--r-- | drivers/input/mouse/bcm5974.c | 1 | ||||
| -rw-r--r-- | drivers/input/mouse/cypress_ps2.c | 31 | ||||
| -rw-r--r-- | drivers/input/mouse/elantech.c | 94 | ||||
| -rw-r--r-- | drivers/input/mouse/elantech.h | 1 | ||||
| -rw-r--r-- | drivers/input/mouse/gpio_mouse.c | 3 | ||||
| -rw-r--r-- | drivers/input/mouse/logips2pp.c | 2 | ||||
| -rw-r--r-- | drivers/input/mouse/navpoint.c | 1 | ||||
| -rw-r--r-- | drivers/input/mouse/pxa930_trkball.c | 3 | ||||
| -rw-r--r-- | drivers/input/mouse/sermouse.c | 1 | ||||
| -rw-r--r-- | drivers/input/mouse/synaptics.c | 96 | ||||
| -rw-r--r-- | drivers/input/mouse/synaptics_usb.c | 1 | ||||
| -rw-r--r-- | drivers/input/mouse/vsxxxaa.c | 1 | 
16 files changed, 687 insertions, 126 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index effa9c5f2c5..366fc7ad5eb 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -17,7 +17,7 @@ config MOUSE_PS2  	default y  	select SERIO  	select SERIO_LIBPS2 -	select SERIO_I8042 if X86 +	select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO  	select SERIO_GSCPS2 if GSC  	help  	  Say Y here if you have a PS/2 mouse connected to your system. This @@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP  	default y  	depends on MOUSE_PS2  	help -	  Say Y here if you have a Logictech PS/2++ mouse connected to +	  Say Y here if you have a Logitech PS/2++ mouse connected to  	  your system.  	  If unsure, say Y. diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 7c5d72a6a26..fb15c64ffb9 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -70,6 +70,25 @@ static const struct alps_nibble_commands alps_v4_nibble_commands[] = {  	{ PSMOUSE_CMD_SETSCALE11,	0x00 }, /* f */  }; +static const struct alps_nibble_commands alps_v6_nibble_commands[] = { +	{ PSMOUSE_CMD_ENABLE,		0x00 }, /* 0 */ +	{ PSMOUSE_CMD_SETRATE,		0x0a }, /* 1 */ +	{ PSMOUSE_CMD_SETRATE,		0x14 }, /* 2 */ +	{ PSMOUSE_CMD_SETRATE,		0x28 }, /* 3 */ +	{ PSMOUSE_CMD_SETRATE,		0x3c }, /* 4 */ +	{ PSMOUSE_CMD_SETRATE,		0x50 }, /* 5 */ +	{ PSMOUSE_CMD_SETRATE,		0x64 }, /* 6 */ +	{ PSMOUSE_CMD_SETRATE,		0xc8 }, /* 7 */ +	{ PSMOUSE_CMD_GETID,		0x00 }, /* 8 */ +	{ PSMOUSE_CMD_GETINFO,		0x00 }, /* 9 */ +	{ PSMOUSE_CMD_SETRES,		0x00 }, /* a */ +	{ PSMOUSE_CMD_SETRES,		0x01 }, /* b */ +	{ PSMOUSE_CMD_SETRES,		0x02 }, /* c */ +	{ PSMOUSE_CMD_SETRES,		0x03 }, /* d */ +	{ PSMOUSE_CMD_SETSCALE21,	0x00 }, /* e */ +	{ PSMOUSE_CMD_SETSCALE11,	0x00 }, /* f */ +}; +  #define ALPS_DUALPOINT		0x02	/* touchpad has trackstick */  #define ALPS_PASS		0x04	/* device has a pass-through port */ @@ -103,6 +122,7 @@ static const struct alps_model_info alps_model_data[] = {  	/* Dell Latitude E5500, E6400, E6500, Precision M4400 */  	{ { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,  		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, +	{ { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT },		/* Dell XT2 */  	{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS },		/* Dell Vostro 1400 */  	{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,  		ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },				/* Toshiba Tecra A11-11L */ @@ -257,6 +277,57 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)  }  /* + * Process bitmap data for V5 protocols. Return value is null. + * + * The bitmaps don't have enough data to track fingers, so this function + * only generates points representing a bounding box of at most two contacts. + * These two points are returned in x1, y1, x2, and y2. + */ +static void alps_process_bitmap_dolphin(struct alps_data *priv, +					struct alps_fields *fields, +					int *x1, int *y1, int *x2, int *y2) +{ +	int box_middle_x, box_middle_y; +	unsigned int x_map, y_map; +	unsigned char start_bit, end_bit; +	unsigned char x_msb, x_lsb, y_msb, y_lsb; + +	x_map = fields->x_map; +	y_map = fields->y_map; + +	if (!x_map || !y_map) +		return; + +	/* Get Most-significant and Least-significant bit */ +	x_msb = fls(x_map); +	x_lsb = ffs(x_map); +	y_msb = fls(y_map); +	y_lsb = ffs(y_map); + +	/* Most-significant bit should never exceed max sensor line number */ +	if (x_msb > priv->x_bits || y_msb > priv->y_bits) +		return; + +	*x1 = *y1 = *x2 = *y2 = 0; + +	if (fields->fingers > 1) { +		start_bit = priv->x_bits - x_msb; +		end_bit = priv->x_bits - x_lsb; +		box_middle_x = (priv->x_max * (start_bit + end_bit)) / +				(2 * (priv->x_bits - 1)); + +		start_bit = y_lsb - 1; +		end_bit = y_msb - 1; +		box_middle_y = (priv->y_max * (start_bit + end_bit)) / +				(2 * (priv->y_bits - 1)); +		*x1 = fields->x; +		*y1 = fields->y; +		*x2 = 2 * box_middle_x - *x1; +		*y2 = 2 * box_middle_y - *y1; +	} +} + +/*   * Process bitmap data from v3 and v4 protocols. Returns the number of   * fingers detected. A return value of 0 means at least one of the   * bitmaps was empty. @@ -461,7 +532,8 @@ static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)  	f->ts_middle = !!(p[3] & 0x40);  } -static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p) +static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, +				 struct psmouse *psmouse)  {  	f->first_mp = !!(p[4] & 0x40);  	f->is_mp = !!(p[0] & 0x40); @@ -482,48 +554,61 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)  	alps_decode_buttons_v3(f, p);  } -static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p) +static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p, +				 struct psmouse *psmouse)  { -	alps_decode_pinnacle(f, p); +	alps_decode_pinnacle(f, p, psmouse);  	f->x_map |= (p[5] & 0x10) << 11;  	f->y_map |= (p[5] & 0x20) << 6;  } -static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p) +static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p, +				struct psmouse *psmouse)  { +	u64 palm_data = 0; +	struct alps_data *priv = psmouse->private; +  	f->first_mp = !!(p[0] & 0x02);  	f->is_mp = !!(p[0] & 0x20); -	f->fingers = ((p[0] & 0x6) >> 1 | +	if (!f->is_mp) { +		f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); +		f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); +		f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; +		alps_decode_buttons_v3(f, p); +	} else { +		f->fingers = ((p[0] & 0x6) >> 1 |  		     (p[0] & 0x10) >> 2); -	f->x_map = ((p[2] & 0x60) >> 5) | -		   ((p[4] & 0x7f) << 2) | -		   ((p[5] & 0x7f) << 9) | -		   ((p[3] & 0x07) << 16) | -		   ((p[3] & 0x70) << 15) | -		   ((p[0] & 0x01) << 22); -	f->y_map = (p[1] & 0x7f) | -		   ((p[2] & 0x1f) << 7); - -	f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); -	f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); -	f->z = (p[0] & 4) ? 0 : p[5] & 0x7f; -	alps_decode_buttons_v3(f, p); +		palm_data = (p[1] & 0x7f) | +			    ((p[2] & 0x7f) << 7) | +			    ((p[4] & 0x7f) << 14) | +			    ((p[5] & 0x7f) << 21) | +			    ((p[3] & 0x07) << 28) | +			    (((u64)p[3] & 0x70) << 27) | +			    (((u64)p[0] & 0x01) << 34); + +		/* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ +		f->y_map = palm_data & (BIT(priv->y_bits) - 1); + +		/* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ +		f->x_map = (palm_data >> priv->y_bits) & +			   (BIT(priv->x_bits) - 1); +	}  } -static void alps_process_touchpad_packet_v3(struct psmouse *psmouse) +static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)  {  	struct alps_data *priv = psmouse->private;  	unsigned char *packet = psmouse->packet;  	struct input_dev *dev = psmouse->dev;  	struct input_dev *dev2 = priv->dev2;  	int x1 = 0, y1 = 0, x2 = 0, y2 = 0; -	int fingers = 0, bmap_fingers; -	struct alps_fields f; +	int fingers = 0, bmap_fn; +	struct alps_fields f = {0}; -	priv->decode_fields(&f, packet); +	priv->decode_fields(&f, packet, psmouse);  	/*  	 * There's no single feature of touchpad position and bitmap packets @@ -540,19 +625,38 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)  		 */  		if (f.is_mp) {  			fingers = f.fingers; -			bmap_fingers = alps_process_bitmap(priv, -							   f.x_map, f.y_map, -							   &x1, &y1, &x2, &y2); - -			/* -			 * We shouldn't report more than one finger if -			 * we don't have two coordinates. -			 */ -			if (fingers > 1 && bmap_fingers < 2) -				fingers = bmap_fingers; - -			/* Now process position packet */ -			priv->decode_fields(&f, priv->multi_data); +			if (priv->proto_version == ALPS_PROTO_V3) { +				bmap_fn = alps_process_bitmap(priv, f.x_map, +							      f.y_map, &x1, &y1, +							      &x2, &y2); + +				/* +				 * We shouldn't report more than one finger if +				 * we don't have two coordinates. +				 */ +				if (fingers > 1 && bmap_fn < 2) +					fingers = bmap_fn; + +				/* Now process position packet */ +				priv->decode_fields(&f, priv->multi_data, +						    psmouse); +			} else { +				/* +				 * Because Dolphin uses position packet's +				 * coordinate data as Pt1 and uses it to +				 * calculate Pt2, so we need to do position +				 * packet decode first. +				 */ +				priv->decode_fields(&f, priv->multi_data, +						    psmouse); + +				/* +				 * Since Dolphin's finger number is reliable, +				 * there is no need to compare with bmap_fn. +				 */ +				alps_process_bitmap_dolphin(priv, &f, &x1, &y1, +							    &x2, &y2); +			}  		} else {  			priv->multi_packet = 0;  		} @@ -642,7 +746,77 @@ static void alps_process_packet_v3(struct psmouse *psmouse)  		return;  	} -	alps_process_touchpad_packet_v3(psmouse); +	alps_process_touchpad_packet_v3_v5(psmouse); +} + +static void alps_process_packet_v6(struct psmouse *psmouse) +{ +	struct alps_data *priv = psmouse->private; +	unsigned char *packet = psmouse->packet; +	struct input_dev *dev = psmouse->dev; +	struct input_dev *dev2 = priv->dev2; +	int x, y, z, left, right, middle; + +	/* +	 * We can use Byte5 to distinguish if the packet is from Touchpad +	 * or Trackpoint. +	 * Touchpad:	0 - 0x7E +	 * Trackpoint:	0x7F +	 */ +	if (packet[5] == 0x7F) { +		/* It should be a DualPoint when received Trackpoint packet */ +		if (!(priv->flags & ALPS_DUALPOINT)) +			return; + +		/* Trackpoint packet */ +		x = packet[1] | ((packet[3] & 0x20) << 2); +		y = packet[2] | ((packet[3] & 0x40) << 1); +		z = packet[4]; +		left = packet[3] & 0x01; +		right = packet[3] & 0x02; +		middle = packet[3] & 0x04; + +		/* To prevent the cursor jump when finger lifted */ +		if (x == 0x7F && y == 0x7F && z == 0x7F) +			x = y = z = 0; + +		/* Divide 4 since trackpoint's speed is too fast */ +		input_report_rel(dev2, REL_X, (char)x / 4); +		input_report_rel(dev2, REL_Y, -((char)y / 4)); + +		input_report_key(dev2, BTN_LEFT, left); +		input_report_key(dev2, BTN_RIGHT, right); +		input_report_key(dev2, BTN_MIDDLE, middle); + +		input_sync(dev2); +		return; +	} + +	/* Touchpad packet */ +	x = packet[1] | ((packet[3] & 0x78) << 4); +	y = packet[2] | ((packet[4] & 0x78) << 4); +	z = packet[5]; +	left = packet[3] & 0x01; +	right = packet[3] & 0x02; + +	if (z > 30) +		input_report_key(dev, BTN_TOUCH, 1); +	if (z < 25) +		input_report_key(dev, BTN_TOUCH, 0); + +	if (z > 0) { +		input_report_abs(dev, ABS_X, x); +		input_report_abs(dev, ABS_Y, y); +	} + +	input_report_abs(dev, ABS_PRESSURE, z); +	input_report_key(dev, BTN_TOOL_FINGER, z > 0); + +	/* v6 touchpad does not have middle button */ +	input_report_key(dev, BTN_LEFT, left); +	input_report_key(dev, BTN_RIGHT, right); + +	input_sync(dev);  }  static void alps_process_packet_v4(struct psmouse *psmouse) @@ -897,7 +1071,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)  	}  	/* Bytes 2 - pktsize should have 0 in the highest bit */ -	if (priv->proto_version != ALPS_PROTO_V5 && +	if ((priv->proto_version < ALPS_PROTO_V5) &&  	    psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&  	    (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {  		psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", @@ -1085,6 +1259,80 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)  	return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);  } +static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word) +{ +	int i, nibble; + +	/* +	 * b0-b11 are valid bits, send sequence is inverse. +	 * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1 +	 */ +	for (i = 0; i <= 8; i += 4) { +		nibble = (word >> i) & 0xf; +		if (alps_command_mode_send_nibble(psmouse, nibble)) +			return -1; +	} + +	return 0; +} + +static int alps_monitor_mode_write_reg(struct psmouse *psmouse, +				       u16 addr, u16 value) +{ +	struct ps2dev *ps2dev = &psmouse->ps2dev; + +	/* 0x0A0 is the command to write the word */ +	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) || +	    alps_monitor_mode_send_word(psmouse, 0x0A0) || +	    alps_monitor_mode_send_word(psmouse, addr) || +	    alps_monitor_mode_send_word(psmouse, value) || +	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) +		return -1; + +	return 0; +} + +static int alps_monitor_mode(struct psmouse *psmouse, bool enable) +{ +	struct ps2dev *ps2dev = &psmouse->ps2dev; + +	if (enable) { +		/* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */ +		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || +		    ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO)) +			return -1; +	} else { +		/* EC to exit monitor mode */ +		if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP)) +			return -1; +	} + +	return 0; +} + +static int alps_absolute_mode_v6(struct psmouse *psmouse) +{ +	u16 reg_val = 0x181; +	int ret = -1; + +	/* enter monitor mode, to write the register */ +	if (alps_monitor_mode(psmouse, true)) +		return -1; + +	ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val); + +	if (alps_monitor_mode(psmouse, false)) +		ret = -1; + +	return ret; +} +  static int alps_get_status(struct psmouse *psmouse, char *param)  {  	/* Get status: 0xF5 0xF5 0xF5 0xE9 */ @@ -1189,6 +1437,32 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)  	return 0;  } +static int alps_hw_init_v6(struct psmouse *psmouse) +{ +	unsigned char param[2] = {0xC8, 0x14}; + +	/* Enter passthrough mode to let trackpoint enter 6byte raw mode */ +	if (alps_passthrough_mode_v2(psmouse, true)) +		return -1; + +	if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +	    ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +	    ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || +	    ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || +	    ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) +		return -1; + +	if (alps_passthrough_mode_v2(psmouse, false)) +		return -1; + +	if (alps_absolute_mode_v6(psmouse)) { +		psmouse_err(psmouse, "Failed to enable absolute mode\n"); +		return -1; +	} + +	return 0; +} +  /*   * Enable or disable passthrough mode to the trackstick.   */ @@ -1519,6 +1793,52 @@ error:  	return -1;  } +static int alps_dolphin_get_device_area(struct psmouse *psmouse, +					struct alps_data *priv) +{ +	struct ps2dev *ps2dev = &psmouse->ps2dev; +	unsigned char param[4] = {0}; +	int num_x_electrode, num_y_electrode; + +	if (alps_enter_command_mode(psmouse)) +		return -1; + +	param[0] = 0x0a; +	if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || +	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || +	    ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || +	    ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || +	    ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE)) +		return -1; + +	if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) +		return -1; + +	/* +	 * Dolphin's sensor line number is not fixed. It can be calculated +	 * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. +	 * Further more, we can get device's x_max and y_max by multiplying +	 * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. +	 * +	 * e.g. When we get register's sensor_x = 11 & sensor_y = 8, +	 *	real sensor line number X = 11 + 8 = 19, and +	 *	real sensor line number Y = 8 + 1 = 9. +	 *	So, x_max = (19 - 1) * 64 = 1152, and +	 *	    y_max = (9 - 1) * 64 = 512. +	 */ +	num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F); +	num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F); +	priv->x_bits = num_x_electrode; +	priv->y_bits = num_y_electrode; +	priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; +	priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; + +	if (alps_exit_command_mode(psmouse)) +		return -1; + +	return 0; +} +  static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)  {  	struct ps2dev *ps2dev = &psmouse->ps2dev; @@ -1553,6 +1873,8 @@ static void alps_set_defaults(struct alps_data *priv)  		priv->hw_init = alps_hw_init_v1_v2;  		priv->process_packet = alps_process_packet_v1_v2;  		priv->set_abs_params = alps_set_abs_params_st; +		priv->x_max = 1023; +		priv->y_max = 767;  		break;  	case ALPS_PROTO_V3:  		priv->hw_init = alps_hw_init_v3; @@ -1571,19 +1893,27 @@ static void alps_set_defaults(struct alps_data *priv)  		break;  	case ALPS_PROTO_V5:  		priv->hw_init = alps_hw_init_dolphin_v1; -		priv->process_packet = alps_process_packet_v3; +		priv->process_packet = alps_process_touchpad_packet_v3_v5;  		priv->decode_fields = alps_decode_dolphin;  		priv->set_abs_params = alps_set_abs_params_mt;  		priv->nibble_commands = alps_v3_nibble_commands;  		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;  		priv->byte0 = 0xc8; -		priv->mask0 = 0xc8; +		priv->mask0 = 0xd8;  		priv->flags = 0;  		priv->x_max = 1360;  		priv->y_max = 660;  		priv->x_bits = 23;  		priv->y_bits = 12;  		break; +	case ALPS_PROTO_V6: +		priv->hw_init = alps_hw_init_v6; +		priv->process_packet = alps_process_packet_v6; +		priv->set_abs_params = alps_set_abs_params_st; +		priv->nibble_commands = alps_v6_nibble_commands; +		priv->x_max = 2047; +		priv->y_max = 1535; +		break;  	}  } @@ -1645,11 +1975,13 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)  	if (alps_match_table(psmouse, priv, e7, ec) == 0) {  		return 0;  	} else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && -		   ec[0] == 0x73 && ec[1] == 0x01) { +		   ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {  		priv->proto_version = ALPS_PROTO_V5;  		alps_set_defaults(priv); - -		return 0; +		if (alps_dolphin_get_device_area(psmouse, priv)) +			return -EIO; +		else +			return 0;  	} else if (ec[0] == 0x88 && ec[1] == 0x08) {  		priv->proto_version = ALPS_PROTO_V3;  		alps_set_defaults(priv); @@ -1705,8 +2037,8 @@ static void alps_disconnect(struct psmouse *psmouse)  static void alps_set_abs_params_st(struct alps_data *priv,  				   struct input_dev *dev1)  { -	input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0); -	input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0); +	input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); +	input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);  }  static void alps_set_abs_params_mt(struct alps_data *priv, @@ -1792,7 +2124,7 @@ int alps_init(struct psmouse *psmouse)  	snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);  	dev2->phys = priv->phys;  	dev2->name = (priv->flags & ALPS_DUALPOINT) ? -		     "DualPoint Stick" : "PS/2 Mouse"; +		     "DualPoint Stick" : "ALPS PS/2 Device";  	dev2->id.bustype = BUS_I8042;  	dev2->id.vendor  = 0x0002;  	dev2->id.product = PSMOUSE_ALPS; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index eee59853b9c..03f88b6940c 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -17,6 +17,11 @@  #define ALPS_PROTO_V3	3  #define ALPS_PROTO_V4	4  #define ALPS_PROTO_V5	5 +#define ALPS_PROTO_V6	6 + +#define DOLPHIN_COUNT_PER_ELECTRODE	64 +#define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */ +#define DOLPHIN_PROFILE_YOFFSET		1	/* y-electrode offset */  /**   * struct alps_model_info - touchpad ID table @@ -145,7 +150,8 @@ struct alps_data {  	int (*hw_init)(struct psmouse *psmouse);  	void (*process_packet)(struct psmouse *psmouse); -	void (*decode_fields)(struct alps_fields *f, unsigned char *p); +	void (*decode_fields)(struct alps_fields *f, unsigned char *p, +			      struct psmouse *psmouse);  	void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);  	int prev_fin; diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index e42f1fa8cdc..ef234c9b2f2 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -30,7 +30,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb/input.h> @@ -49,6 +48,7 @@ struct atp_info {  	int yfact;				/* Y multiplication factor */  	int datalen;				/* size of USB transfers */  	void (*callback)(struct urb *);		/* callback function */ +	int fuzz;				/* fuzz touchpad generates */  };  static void atp_complete_geyser_1_2(struct urb *urb); @@ -62,6 +62,7 @@ static const struct atp_info fountain_info = {  	.yfact		= 43,  	.datalen	= 81,  	.callback	= atp_complete_geyser_1_2, +	.fuzz		= 16,  };  static const struct atp_info geyser1_info = { @@ -72,6 +73,7 @@ static const struct atp_info geyser1_info = {  	.yfact		= 43,  	.datalen	= 81,  	.callback	= atp_complete_geyser_1_2, +	.fuzz		= 16,  };  static const struct atp_info geyser2_info = { @@ -82,6 +84,7 @@ static const struct atp_info geyser2_info = {  	.yfact		= 43,  	.datalen	= 64,  	.callback	= atp_complete_geyser_1_2, +	.fuzz		= 0,  };  static const struct atp_info geyser3_info = { @@ -91,6 +94,7 @@ static const struct atp_info geyser3_info = {  	.yfact		= 64,  	.datalen	= 64,  	.callback	= atp_complete_geyser_3_4, +	.fuzz		= 0,  };  static const struct atp_info geyser4_info = { @@ -100,6 +104,7 @@ static const struct atp_info geyser4_info = {  	.yfact		= 64,  	.datalen	= 64,  	.callback	= atp_complete_geyser_3_4, +	.fuzz		= 0,  };  #define ATP_DEVICE(prod, info)					\ @@ -156,8 +161,11 @@ MODULE_DEVICE_TABLE(usb, atp_table);  #define ATP_XSENSORS	26  #define ATP_YSENSORS	16 -/* amount of fuzz this touchpad generates */ -#define ATP_FUZZ	16 +/* + * The largest possible bank of sensors with additional buffer of 4 extra values + * on either side, for an array of smoothed sensor values. + */ +#define ATP_SMOOTHSIZE	34  /* maximum pressure this driver will report */  #define ATP_PRESSURE	300 @@ -166,7 +174,13 @@ MODULE_DEVICE_TABLE(usb, atp_table);   * Threshold for the touchpad sensors. Any change less than ATP_THRESHOLD is   * ignored.   */ -#define ATP_THRESHOLD	 5 +#define ATP_THRESHOLD	5 + +/* + * How far we'll bitshift our sensor values before averaging them. Mitigates + * rounding errors. + */ +#define ATP_SCALE	12  /* Geyser initialization constants */  #define ATP_GEYSER_MODE_READ_REQUEST_ID		1 @@ -204,11 +218,14 @@ struct atp {  	bool			valid;		/* are the samples valid? */  	bool			size_detect_done;  	bool			overflow_warned; +	int			fingers_old;	/* last reported finger count */  	int			x_old;		/* last reported x/y, */  	int			y_old;		/* used for smoothing */  	signed char		xy_cur[ATP_XSENSORS + ATP_YSENSORS];  	signed char		xy_old[ATP_XSENSORS + ATP_YSENSORS];  	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS]; +	int			smooth[ATP_SMOOTHSIZE]; +	int			smooth_tmp[ATP_SMOOTHSIZE];  	int			idlecount;	/* number of empty packets */  	struct work_struct	work;  }; @@ -327,10 +344,17 @@ static void atp_reinit(struct work_struct *work)  			retval);  } -static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, -			     int *z, int *fingers) +static int atp_calculate_abs(struct atp *dev, int offset, int nb_sensors, +			     int fact, int *z, int *fingers)  { -	int i; +	int i, pass; + +	/* +	 * Use offset to point xy_sensors at the first value in dev->xy_acc +	 * for whichever dimension we're looking at this particular go-round. +	 */ +	int *xy_sensors = dev->xy_acc + offset; +  	/* values to calculate mean */  	int pcum = 0, psum = 0;  	int is_increasing = 0; @@ -342,9 +366,6 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,  			if (is_increasing)  				is_increasing = 0; -			continue; -		} -  		/*  		 * Makes the finger detection more versatile.  For example,  		 * two fingers with no gap will be detected.  Also, my @@ -359,27 +380,63 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,  		 *  		 * - Jason Parekh <jasonparekh@gmail.com>  		 */ -		if (i < 1 || + +		} else if (i < 1 ||  		    (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {  			(*fingers)++;  			is_increasing = 1;  		} else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {  			is_increasing = 0;  		} +	} + +	if (*fingers < 1)     /* No need to continue if no fingers are found. */ +		return 0; +	/* +	 * Use a smoothed version of sensor data for movement calculations, to +	 * combat noise without needing to rely so heavily on a threshold. +	 * This improves tracking. +	 * +	 * The smoothed array is bigger than the original so that the smoothing +	 * doesn't result in edge values being truncated. +	 */ + +	memset(dev->smooth, 0, 4 * sizeof(dev->smooth[0])); +	/* Pull base values, scaled up to help avoid truncation errors. */ +	for (i = 0; i < nb_sensors; i++) +		dev->smooth[i + 4] = xy_sensors[i] << ATP_SCALE; +	memset(&dev->smooth[nb_sensors + 4], 0, 4 * sizeof(dev->smooth[0])); + +	for (pass = 0; pass < 4; pass++) { +		/* Handle edge. */ +		dev->smooth_tmp[0] = (dev->smooth[0] + dev->smooth[1]) / 2; + +		/* Average values with neighbors. */ +		for (i = 1; i < nb_sensors + 7; i++) +			dev->smooth_tmp[i] = (dev->smooth[i - 1] + +					      dev->smooth[i] * 2 + +					      dev->smooth[i + 1]) / 4; + +		/* Handle other edge. */ +		dev->smooth_tmp[i] = (dev->smooth[i - 1] + dev->smooth[i]) / 2; + +		memcpy(dev->smooth, dev->smooth_tmp, sizeof(dev->smooth)); +	} + +	for (i = 0; i < nb_sensors + 8; i++) {  		/* -		 * Subtracts threshold so a high sensor that just passes the -		 * threshold won't skew the calculated absolute coordinate. -		 * Fixes an issue where slowly moving the mouse would -		 * occasionally jump a number of pixels (slowly moving the -		 * finger makes this issue most apparent.) +		 * Skip values if they're small enough to be truncated to 0 +		 * by scale. Mostly noise.  		 */ -		pcum += (xy_sensors[i] - threshold) * i; -		psum += (xy_sensors[i] - threshold); +		if ((dev->smooth[i] >> ATP_SCALE) > 0) { +			pcum += dev->smooth[i] * i; +			psum += dev->smooth[i]; +		}  	}  	if (psum > 0) { -		*z = psum; +		*z = psum >> ATP_SCALE;        /* Scale down pressure output. */  		return pcum * fact / psum;  	} @@ -456,7 +513,7 @@ static void atp_detect_size(struct atp *dev)  			input_set_abs_params(dev->input, ABS_X, 0,  					     (dev->info->xsensors_17 - 1) *  							dev->info->xfact - 1, -					     ATP_FUZZ, 0); +					     dev->info->fuzz, 0);  			break;  		}  	} @@ -472,7 +529,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)  {  	int x, y, x_z, y_z, x_f, y_f;  	int retval, i, j; -	int key; +	int key, fingers;  	struct atp *dev = urb->context;  	int status = atp_status_check(urb); @@ -549,16 +606,18 @@ static void atp_complete_geyser_1_2(struct urb *urb)  	dbg_dump("accumulator", dev->xy_acc); -	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, +	x = atp_calculate_abs(dev, 0, ATP_XSENSORS,  			      dev->info->xfact, &x_z, &x_f); -	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, +	y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,  			      dev->info->yfact, &y_z, &y_f);  	key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; -	if (x && y) { +	fingers = max(x_f, y_f); + +	if (x && y && fingers == dev->fingers_old) {  		if (dev->x_old != -1) { -			x = (dev->x_old * 3 + x) >> 2; -			y = (dev->y_old * 3 + y) >> 2; +			x = (dev->x_old * 7 + x) >> 3; +			y = (dev->y_old * 7 + y) >> 3;  			dev->x_old = x;  			dev->y_old = y; @@ -572,7 +631,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)  			input_report_abs(dev->input, ABS_Y, y);  			input_report_abs(dev->input, ABS_PRESSURE,  					 min(ATP_PRESSURE, x_z + y_z)); -			atp_report_fingers(dev->input, max(x_f, y_f)); +			atp_report_fingers(dev->input, fingers);  		}  		dev->x_old = x;  		dev->y_old = y; @@ -580,6 +639,7 @@ static void atp_complete_geyser_1_2(struct urb *urb)  	} else if (!x && !y) {  		dev->x_old = dev->y_old = -1; +		dev->fingers_old = 0;  		input_report_key(dev->input, BTN_TOUCH, 0);  		input_report_abs(dev->input, ABS_PRESSURE, 0);  		atp_report_fingers(dev->input, 0); @@ -588,6 +648,10 @@ static void atp_complete_geyser_1_2(struct urb *urb)  		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));  	} +	if (fingers != dev->fingers_old) +		dev->x_old = dev->y_old = -1; +	dev->fingers_old = fingers; +  	input_report_key(dev->input, BTN_LEFT, key);  	input_sync(dev->input); @@ -605,7 +669,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)  {  	int x, y, x_z, y_z, x_f, y_f;  	int retval, i, j; -	int key; +	int key, fingers;  	struct atp *dev = urb->context;  	int status = atp_status_check(urb); @@ -661,16 +725,19 @@ static void atp_complete_geyser_3_4(struct urb *urb)  	dbg_dump("accumulator", dev->xy_acc); -	x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS, +	x = atp_calculate_abs(dev, 0, ATP_XSENSORS,  			      dev->info->xfact, &x_z, &x_f); -	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, +	y = atp_calculate_abs(dev, ATP_XSENSORS, ATP_YSENSORS,  			      dev->info->yfact, &y_z, &y_f); +  	key = dev->data[dev->info->datalen - 1] & ATP_STATUS_BUTTON; -	if (x && y) { +	fingers = max(x_f, y_f); + +	if (x && y && fingers == dev->fingers_old) {  		if (dev->x_old != -1) { -			x = (dev->x_old * 3 + x) >> 2; -			y = (dev->y_old * 3 + y) >> 2; +			x = (dev->x_old * 7 + x) >> 3; +			y = (dev->y_old * 7 + y) >> 3;  			dev->x_old = x;  			dev->y_old = y; @@ -684,7 +751,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)  			input_report_abs(dev->input, ABS_Y, y);  			input_report_abs(dev->input, ABS_PRESSURE,  					 min(ATP_PRESSURE, x_z + y_z)); -			atp_report_fingers(dev->input, max(x_f, y_f)); +			atp_report_fingers(dev->input, fingers);  		}  		dev->x_old = x;  		dev->y_old = y; @@ -692,6 +759,7 @@ static void atp_complete_geyser_3_4(struct urb *urb)  	} else if (!x && !y) {  		dev->x_old = dev->y_old = -1; +		dev->fingers_old = 0;  		input_report_key(dev->input, BTN_TOUCH, 0);  		input_report_abs(dev->input, ABS_PRESSURE, 0);  		atp_report_fingers(dev->input, 0); @@ -700,6 +768,10 @@ static void atp_complete_geyser_3_4(struct urb *urb)  		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));  	} +	if (fingers != dev->fingers_old) +		dev->x_old = dev->y_old = -1; +	dev->fingers_old = fingers; +  	input_report_key(dev->input, BTN_LEFT, key);  	input_sync(dev->input); @@ -844,10 +916,10 @@ static int atp_probe(struct usb_interface *iface,  	input_set_abs_params(input_dev, ABS_X, 0,  			     (dev->info->xsensors - 1) * dev->info->xfact - 1, -			     ATP_FUZZ, 0); +			     dev->info->fuzz, 0);  	input_set_abs_params(input_dev, ABS_Y, 0,  			     (dev->info->ysensors - 1) * dev->info->yfact - 1, -			     ATP_FUZZ, 0); +			     dev->info->fuzz, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, ATP_PRESSURE, 0, 0);  	set_bit(EV_KEY, input_dev->evbit); diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index a73f9618b0a..c329cdb0b91 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -34,7 +34,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb/input.h> diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index f51765fff05..8af34ffe208 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c @@ -15,7 +15,6 @@   * the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/slab.h> @@ -410,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,  	__clear_bit(REL_X, input->relbit);  	__clear_bit(REL_Y, input->relbit); -	__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);  	__set_bit(EV_KEY, input->evbit);  	__set_bit(BTN_LEFT, input->keybit);  	__set_bit(BTN_RIGHT, input->keybit); @@ -439,7 +437,7 @@ static int cypress_get_finger_count(unsigned char header_byte)  			case 2: return 5;  			default:  				/* Invalid contact (e.g. palm). Ignore it. */ -				return -1; +				return 0;  		}  	} @@ -452,17 +450,10 @@ static int cypress_parse_packet(struct psmouse *psmouse,  {  	unsigned char *packet = psmouse->packet;  	unsigned char header_byte = packet[0]; -	int contact_cnt;  	memset(report_data, 0, sizeof(struct cytp_report_data)); -	contact_cnt = cypress_get_finger_count(header_byte); - -	if (contact_cnt < 0) /* e.g. palm detect */ -		return -EINVAL; - -	report_data->contact_cnt = contact_cnt; - +	report_data->contact_cnt = cypress_get_finger_count(header_byte);  	report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;  	if (report_data->contact_cnt == 1) { @@ -535,11 +526,9 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)  	int slots[CYTP_MAX_MT_SLOTS];  	int n; -	if (cypress_parse_packet(psmouse, cytp, &report_data)) -		return; +	cypress_parse_packet(psmouse, cytp, &report_data);  	n = report_data.contact_cnt; -  	if (n > CYTP_MAX_MT_SLOTS)  		n = CYTP_MAX_MT_SLOTS; @@ -605,10 +594,6 @@ static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)  		return PSMOUSE_BAD_DATA;  	contact_cnt = cypress_get_finger_count(packet[0]); - -	if (contact_cnt < 0) -		return PSMOUSE_BAD_DATA; -  	if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)  		cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);  	else @@ -679,15 +664,15 @@ int cypress_init(struct psmouse *psmouse)  {  	struct cytp_data *cytp; -	cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL); -	psmouse->private = (void *)cytp; -	if (cytp == NULL) +	cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL); +	if (!cytp)  		return -ENOMEM; -	cypress_reset(psmouse); - +	psmouse->private = cytp;  	psmouse->pktsize = 8; +	cypress_reset(psmouse); +  	if (cypress_query_hardware(psmouse)) {  		psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");  		goto err_exit; diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 8551dcaf24d..ee2a04d90d2 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -11,6 +11,7 @@   */  #include <linux/delay.h> +#include <linux/dmi.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/input.h> @@ -472,8 +473,15 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,  	input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);  	input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);  	input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); -	input_report_key(dev, BTN_LEFT, packet[0] & 0x01); -	input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); + +	/* For clickpads map both buttons to BTN_LEFT */ +	if (etd->fw_version & 0x001000) { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x03); +	} else { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x01); +		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); +	} +  	input_report_abs(dev, ABS_PRESSURE, pres);  	input_report_abs(dev, ABS_TOOL_WIDTH, width); @@ -483,9 +491,17 @@ static void elantech_report_absolute_v3(struct psmouse *psmouse,  static void elantech_input_sync_v4(struct psmouse *psmouse)  {  	struct input_dev *dev = psmouse->dev; +	struct elantech_data *etd = psmouse->private;  	unsigned char *packet = psmouse->packet; -	input_report_key(dev, BTN_LEFT, packet[0] & 0x01); +	/* For clickpads map both buttons to BTN_LEFT */ +	if (etd->fw_version & 0x001000) { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x03); +	} else { +		input_report_key(dev, BTN_LEFT, packet[0] & 0x01); +		input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); +	} +  	input_mt_report_pointer_emulation(dev, true);  	input_sync(dev);  } @@ -830,7 +846,11 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse)  		break;  	case 3: -		etd->reg_10 = 0x0b; +		if (etd->set_hw_resolution) +			etd->reg_10 = 0x0b; +		else +			etd->reg_10 = 0x01; +  		if (elantech_write_reg(psmouse, 0x10, etd->reg_10))  			rc = -1; @@ -984,6 +1004,44 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,  }  /* + * Advertise INPUT_PROP_BUTTONPAD for clickpads. The testing of bit 12 in + * fw_version for this is based on the following fw_version & caps table: + * + * Laptop-model:           fw_version:     caps:           buttons: + * Acer S3                 0x461f00        10, 13, 0e      clickpad + * Acer S7-392             0x581f01        50, 17, 0d      clickpad + * Acer V5-131             0x461f02        01, 16, 0c      clickpad + * Acer V5-551             0x461f00        ?               clickpad + * Asus K53SV              0x450f01        78, 15, 0c      2 hw buttons + * Asus G46VW              0x460f02        00, 18, 0c      2 hw buttons + * Asus G750JX             0x360f00        00, 16, 0c      2 hw buttons + * Asus UX31               0x361f00        20, 15, 0e      clickpad + * Asus UX32VD             0x361f02        00, 15, 0e      clickpad + * Avatar AVIU-145A2       0x361f00        ?               clickpad + * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons + * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*) + * Samsung NF210           0x150b00        78, 14, 0a      2 hw buttons + * Samsung NP770Z5E        0x575f01        10, 15, 0f      clickpad + * Samsung NP700Z5B        0x361f06        21, 15, 0f      clickpad + * Samsung NP900X3E-A02    0x575f03        ?               clickpad + * Samsung NP-QX410        0x851b00        19, 14, 0c      clickpad + * Samsung RC512           0x450f00        08, 15, 0c      2 hw buttons + * Samsung RF710           0x450f00        ?               2 hw buttons + * System76 Pangolin       0x250f01        ?               2 hw buttons + * (*) + 3 trackpoint buttons + */ +static void elantech_set_buttonpad_prop(struct psmouse *psmouse) +{ +	struct input_dev *dev = psmouse->dev; +	struct elantech_data *etd = psmouse->private; + +	if (etd->fw_version & 0x001000) { +		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); +		__clear_bit(BTN_RIGHT, dev->keybit); +	} +} + +/*   * Set the appropriate event bits for the input subsystem   */  static int elantech_set_input_params(struct psmouse *psmouse) @@ -1026,6 +1084,8 @@ static int elantech_set_input_params(struct psmouse *psmouse)  		__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);  		/* fall through */  	case 3: +		if (etd->hw_version == 3) +			elantech_set_buttonpad_prop(psmouse);  		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);  		input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);  		if (etd->reports_pressure) { @@ -1047,9 +1107,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)  			 */  			psmouse_warn(psmouse, "couldn't query resolution data.\n");  		} -		/* v4 is clickpad, with only one button. */ -		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); -		__clear_bit(BTN_RIGHT, dev->keybit); +		elantech_set_buttonpad_prop(psmouse);  		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);  		/* For X to recognize me as touchpad. */  		input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); @@ -1292,6 +1350,23 @@ static int elantech_reconnect(struct psmouse *psmouse)  }  /* + * Some hw_version 3 models go into error state when we try to set + * bit 3 and/or bit 1 of r10. + */ +static const struct dmi_system_id no_hw_res_dmi_table[] = { +#if defined(CONFIG_DMI) && defined(CONFIG_X86) +	{ +		/* Gigabyte U2442 */ +		.matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), +			DMI_MATCH(DMI_PRODUCT_NAME, "U2442"), +		}, +	}, +#endif +	{ } +}; + +/*   * determine hardware version and set some properties according to it.   */  static int elantech_set_properties(struct elantech_data *etd) @@ -1313,6 +1388,8 @@ static int elantech_set_properties(struct elantech_data *etd)  			break;  		case 6:  		case 7: +		case 8: +		case 9:  			etd->hw_version = 4;  			break;  		default: @@ -1349,6 +1426,9 @@ static int elantech_set_properties(struct elantech_data *etd)  	 */  	etd->crc_enabled = ((etd->fw_version & 0x4000) == 0x4000); +	/* Enable real hardware resolution on hw_version 3 ? */ +	etd->set_hw_resolution = !dmi_check_system(no_hw_res_dmi_table); +  	return 0;  } diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index 036a04abaef..9e0e2a1f340 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -130,6 +130,7 @@ struct elantech_data {  	bool jumpy_cursor;  	bool reports_pressure;  	bool crc_enabled; +	bool set_hw_resolution;  	unsigned char hw_version;  	unsigned int fw_version;  	unsigned int single_finger_reports; diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index 6b44413f54e..8c7d94200bd 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -8,7 +8,6 @@   * published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/input-polldev.h> @@ -48,7 +47,7 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)  static int gpio_mouse_probe(struct platform_device *pdev)  { -	struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data; +	struct gpio_mouse_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct input_polled_dev *input_poll;  	struct input_dev *input;  	int pin, i; diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 84de2fc6acc..136e222e2a1 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -220,7 +220,7 @@ static const struct ps2pp_info *get_model_info(unsigned char model)  		{ 61,	PS2PP_KIND_MX,					/* MX700 */  				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |  				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, -		{ 66,	PS2PP_KIND_MX,					/* MX3100 reciver */ +		{ 66,	PS2PP_KIND_MX,					/* MX3100 receiver */  				PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |  				PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },  		{ 72,	PS2PP_KIND_TRACKMAN,	0 },			/* T-CH11: TrackMan Marble */ diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c index 0b8d33591de..1ccc88af1f0 100644 --- a/drivers/input/mouse/navpoint.c +++ b/drivers/input/mouse/navpoint.c @@ -9,7 +9,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/module.h>  #include <linux/platform_device.h>  #include <linux/clk.h> diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index 0ecb9e7945e..9b4d9a59e22 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -10,7 +10,6 @@   *  published by the Free Software Foundation.   */ -#include <linux/init.h>  #include <linux/input.h>  #include <linux/interrupt.h>  #include <linux/module.h> @@ -166,7 +165,7 @@ static int pxa930_trkball_probe(struct platform_device *pdev)  	if (!trkball)  		return -ENOMEM; -	trkball->pdata = pdev->dev.platform_data; +	trkball->pdata = dev_get_platdata(&pdev->dev);  	if (!trkball->pdata) {  		dev_err(&pdev->dev, "no platform data defined\n");  		error = -EINVAL; diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index d5928fd0c91..8df526620eb 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -32,7 +32,6 @@  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC	"Serial mouse driver" diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 26386f9d256..ef9e0b8a9aa 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -117,6 +117,82 @@ void synaptics_reset(struct psmouse *psmouse)  }  #ifdef CONFIG_MOUSE_PS2_SYNAPTICS +struct min_max_quirk { +	const char * const *pnp_ids; +	int x_min, x_max, y_min, y_max; +}; + +static const struct min_max_quirk min_max_pnpid_table[] = { +	{ +		(const char * const []){"LEN0033", NULL}, +		1024, 5052, 2258, 4832 +	}, +	{ +		(const char * const []){"LEN0035", "LEN0042", NULL}, +		1232, 5710, 1156, 4696 +	}, +	{ +		(const char * const []){"LEN0034", "LEN0036", "LEN2002", +					"LEN2004", NULL}, +		1024, 5112, 2024, 4832 +	}, +	{ +		(const char * const []){"LEN2001", NULL}, +		1024, 5022, 2508, 4832 +	}, +	{ } +}; + +/* This list has been kindly provided by Synaptics. */ +static const char * const topbuttonpad_pnp_ids[] = { +	"LEN0017", +	"LEN0018", +	"LEN0019", +	"LEN0023", +	"LEN002A", +	"LEN002B", +	"LEN002C", +	"LEN002D", +	"LEN002E", +	"LEN0033", /* Helix */ +	"LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */ +	"LEN0035", /* X240 */ +	"LEN0036", /* T440 */ +	"LEN0037", +	"LEN0038", +	"LEN0041", +	"LEN0042", /* Yoga */ +	"LEN0045", +	"LEN0046", +	"LEN0047", +	"LEN0048", +	"LEN0049", +	"LEN2000", +	"LEN2001", /* Edge E431 */ +	"LEN2002", /* Edge E531 */ +	"LEN2003", +	"LEN2004", /* L440 */ +	"LEN2005", +	"LEN2006", +	"LEN2007", +	"LEN2008", +	"LEN2009", +	"LEN200A", +	"LEN200B", +	NULL +}; + +static bool matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) +{ +	int i; + +	if (!strncmp(psmouse->ps2dev.serio->firmware_id, "PNP:", 4)) +		for (i = 0; ids[i]; i++) +			if (strstr(psmouse->ps2dev.serio->firmware_id, ids[i])) +				return true; + +	return false; +}  /*****************************************************************************   *	Synaptics communications functions @@ -265,10 +341,12 @@ static int synaptics_identify(struct psmouse *psmouse)   * Read touchpad resolution and maximum reported coordinates   * Resolution is left zero if touchpad does not support the query   */ +  static int synaptics_resolution(struct psmouse *psmouse)  {  	struct synaptics_data *priv = psmouse->private;  	unsigned char resp[3]; +	int i;  	if (SYN_ID_MAJOR(priv->identity) < 4)  		return 0; @@ -280,6 +358,16 @@ static int synaptics_resolution(struct psmouse *psmouse)  		}  	} +	for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { +		if (matches_pnp_id(psmouse, min_max_pnpid_table[i].pnp_ids)) { +			priv->x_min = min_max_pnpid_table[i].x_min; +			priv->x_max = min_max_pnpid_table[i].x_max; +			priv->y_min = min_max_pnpid_table[i].y_min; +			priv->y_max = min_max_pnpid_table[i].y_max; +			return 0; +		} +	} +  	if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 &&  	    SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) {  		if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { @@ -1244,8 +1332,10 @@ static void set_abs_position_params(struct input_dev *dev,  	input_abs_set_res(dev, y_code, priv->y_res);  } -static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) +static void set_input_params(struct psmouse *psmouse, +			     struct synaptics_data *priv)  { +	struct input_dev *dev = psmouse->dev;  	int i;  	/* Things that apply to both modes */ @@ -1314,6 +1404,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)  	if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {  		__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); +		if (matches_pnp_id(psmouse, topbuttonpad_pnp_ids)) +			__set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit);  		/* Clickpads report only left button */  		__clear_bit(BTN_RIGHT, dev->keybit);  		__clear_bit(BTN_MIDDLE, dev->keybit); @@ -1538,7 +1630,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)  		     priv->capabilities, priv->ext_cap, priv->ext_cap_0c,  		     priv->board_id, priv->firmware_id); -	set_input_params(psmouse->dev, priv); +	set_input_params(psmouse, priv);  	/*  	 * Encode touchpad model so that it can be used to set diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c index 64cf34ea760..e122bda16aa 100644 --- a/drivers/input/mouse/synaptics_usb.c +++ b/drivers/input/mouse/synaptics_usb.c @@ -39,7 +39,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/moduleparam.h> diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index e900d465aaf..38298232124 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -82,7 +82,6 @@  #include <linux/interrupt.h>  #include <linux/input.h>  #include <linux/serio.h> -#include <linux/init.h>  #define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet"  | 
