diff options
Diffstat (limited to 'drivers/input/mouse/elantech.c')
| -rw-r--r-- | drivers/input/mouse/elantech.c | 94 | 
1 files changed, 87 insertions, 7 deletions
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;  }  | 
