mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 01:10:04 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: "An update to Synaptics PS/2 driver to handle "ForcePads" (currently found in HP EliteBook 1040 laptops), a change for Elan PS/2 driver to detect newer touchpads, bunch of devices get annotated as Trackpoint and/or Pointer to help userspace classify and handle them, plus assorted driver fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: serport - add compat handling for SPIOCSTYPE ioctl Input: atmel_mxt_ts - fix double free of input device Input: synaptics - add support for ForcePads Input: matrix_keypad - use request_any_context_irq() Input: atmel_mxt_ts - downgrade warning about empty interrupts Input: wm971x - fix typo in module parameter description Input: cap1106 - fix register definition Input: add missing POINTER / DIRECT properties to a bunch of drivers Input: add INPUT_PROP_POINTING_STICK property Input: elantech - fix detection of touchpad on ASUS s301l
This commit is contained in:
commit
c8c16e3624
14 changed files with 157 additions and 38 deletions
|
@ -33,8 +33,8 @@
|
|||
#define CAP1106_REG_SENSOR_CONFIG 0x22
|
||||
#define CAP1106_REG_SENSOR_CONFIG2 0x23
|
||||
#define CAP1106_REG_SAMPLING_CONFIG 0x24
|
||||
#define CAP1106_REG_CALIBRATION 0x25
|
||||
#define CAP1106_REG_INT_ENABLE 0x26
|
||||
#define CAP1106_REG_CALIBRATION 0x26
|
||||
#define CAP1106_REG_INT_ENABLE 0x27
|
||||
#define CAP1106_REG_REPEAT_RATE 0x28
|
||||
#define CAP1106_REG_MT_CONFIG 0x2a
|
||||
#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b
|
||||
|
|
|
@ -332,23 +332,24 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev,
|
|||
}
|
||||
|
||||
if (pdata->clustered_irq > 0) {
|
||||
err = request_irq(pdata->clustered_irq,
|
||||
err = request_any_context_irq(pdata->clustered_irq,
|
||||
matrix_keypad_interrupt,
|
||||
pdata->clustered_irq_flags,
|
||||
"matrix-keypad", keypad);
|
||||
if (err) {
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to acquire clustered interrupt\n");
|
||||
goto err_free_rows;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
||||
err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
|
||||
err = request_any_context_irq(
|
||||
gpio_to_irq(pdata->row_gpios[i]),
|
||||
matrix_keypad_interrupt,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"matrix-keypad", keypad);
|
||||
if (err) {
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to acquire interrupt for GPIO line %i\n",
|
||||
pdata->row_gpios[i]);
|
||||
|
|
|
@ -2373,6 +2373,10 @@ int alps_init(struct psmouse *psmouse)
|
|||
dev2->keybit[BIT_WORD(BTN_LEFT)] =
|
||||
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, dev2->propbit);
|
||||
if (priv->flags & ALPS_DUALPOINT)
|
||||
__set_bit(INPUT_PROP_POINTING_STICK, dev2->propbit);
|
||||
|
||||
if (input_register_device(priv->dev2))
|
||||
goto init_fail;
|
||||
|
||||
|
|
|
@ -1331,6 +1331,13 @@ static bool elantech_is_signature_valid(const unsigned char *param)
|
|||
if (param[1] == 0)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Some models have a revision higher then 20. Meaning param[2] may
|
||||
* be 10 or 20, skip the rates check for these.
|
||||
*/
|
||||
if (param[0] == 0x46 && (param[1] & 0xef) == 0x0f && param[2] < 40)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rates); i++)
|
||||
if (param[2] == rates[i])
|
||||
return false;
|
||||
|
@ -1607,6 +1614,10 @@ int elantech_init(struct psmouse *psmouse)
|
|||
tp_dev->keybit[BIT_WORD(BTN_LEFT)] =
|
||||
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
|
||||
BIT_MASK(BTN_RIGHT);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, tp_dev->propbit);
|
||||
__set_bit(INPUT_PROP_POINTING_STICK, tp_dev->propbit);
|
||||
|
||||
error = input_register_device(etd->tp_dev);
|
||||
if (error < 0)
|
||||
goto init_fail_tp_reg;
|
||||
|
|
|
@ -670,6 +670,8 @@ static void psmouse_apply_defaults(struct psmouse *psmouse)
|
|||
__set_bit(REL_X, input_dev->relbit);
|
||||
__set_bit(REL_Y, input_dev->relbit);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
|
||||
psmouse->set_rate = psmouse_set_rate;
|
||||
psmouse->set_resolution = psmouse_set_resolution;
|
||||
psmouse->poll = psmouse_poll;
|
||||
|
|
|
@ -629,10 +629,61 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
|||
((buf[0] & 0x04) >> 1) |
|
||||
((buf[3] & 0x04) >> 2));
|
||||
|
||||
if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
|
||||
SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
|
||||
hw->w == 2) {
|
||||
synaptics_parse_agm(buf, priv, hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
hw->x = (((buf[3] & 0x10) << 8) |
|
||||
((buf[1] & 0x0f) << 8) |
|
||||
buf[4]);
|
||||
hw->y = (((buf[3] & 0x20) << 7) |
|
||||
((buf[1] & 0xf0) << 4) |
|
||||
buf[5]);
|
||||
hw->z = buf[2];
|
||||
|
||||
hw->left = (buf[0] & 0x01) ? 1 : 0;
|
||||
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||||
|
||||
if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
|
||||
if (SYN_CAP_FORCEPAD(priv->ext_cap_0c)) {
|
||||
/*
|
||||
* ForcePads, like Clickpads, use middle button
|
||||
* bits to report primary button clicks.
|
||||
* Unfortunately they report primary button not
|
||||
* only when user presses on the pad above certain
|
||||
* threshold, but also when there are more than one
|
||||
* finger on the touchpad, which interferes with
|
||||
* out multi-finger gestures.
|
||||
*/
|
||||
if (hw->z == 0) {
|
||||
/* No contacts */
|
||||
priv->press = priv->report_press = false;
|
||||
} else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) {
|
||||
/*
|
||||
* Single-finger touch with pressure above
|
||||
* the threshold. If pressure stays long
|
||||
* enough, we'll start reporting primary
|
||||
* button. We rely on the device continuing
|
||||
* sending data even if finger does not
|
||||
* move.
|
||||
*/
|
||||
if (!priv->press) {
|
||||
priv->press_start = jiffies;
|
||||
priv->press = true;
|
||||
} else if (time_after(jiffies,
|
||||
priv->press_start +
|
||||
msecs_to_jiffies(50))) {
|
||||
priv->report_press = true;
|
||||
}
|
||||
} else {
|
||||
priv->press = false;
|
||||
}
|
||||
|
||||
hw->left = priv->report_press;
|
||||
|
||||
} else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
|
||||
/*
|
||||
* Clickpad's button is transmitted as middle button,
|
||||
* however, since it is primary button, we will report
|
||||
|
@ -651,21 +702,6 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
|||
hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
|
||||
}
|
||||
|
||||
if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
|
||||
SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
|
||||
hw->w == 2) {
|
||||
synaptics_parse_agm(buf, priv, hw);
|
||||
return 1;
|
||||
}
|
||||
|
||||
hw->x = (((buf[3] & 0x10) << 8) |
|
||||
((buf[1] & 0x0f) << 8) |
|
||||
buf[4]);
|
||||
hw->y = (((buf[3] & 0x20) << 7) |
|
||||
((buf[1] & 0xf0) << 4) |
|
||||
buf[5]);
|
||||
hw->z = buf[2];
|
||||
|
||||
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
|
||||
((buf[0] ^ buf[3]) & 0x02)) {
|
||||
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
|
||||
|
|
|
@ -78,6 +78,11 @@
|
|||
* 2 0x08 image sensor image sensor tracks 5 fingers, but only
|
||||
* reports 2.
|
||||
* 2 0x20 report min query 0x0f gives min coord reported
|
||||
* 2 0x80 forcepad forcepad is a variant of clickpad that
|
||||
* does not have physical buttons but rather
|
||||
* uses pressure above certain threshold to
|
||||
* report primary clicks. Forcepads also have
|
||||
* clickpad bit set.
|
||||
*/
|
||||
#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
|
||||
#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */
|
||||
|
@ -86,6 +91,7 @@
|
|||
#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
|
||||
#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
|
||||
#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800)
|
||||
#define SYN_CAP_FORCEPAD(ex0c) ((ex0c) & 0x008000)
|
||||
|
||||
/* synaptics modes query bits */
|
||||
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
|
||||
|
@ -177,6 +183,11 @@ struct synaptics_data {
|
|||
*/
|
||||
struct synaptics_hw_state agm;
|
||||
bool agm_pending; /* new AGM packet received */
|
||||
|
||||
/* ForcePad handling */
|
||||
unsigned long press_start;
|
||||
bool press;
|
||||
bool report_press;
|
||||
};
|
||||
|
||||
void synaptics_module_init(void);
|
||||
|
|
|
@ -387,6 +387,7 @@ static int synusb_probe(struct usb_interface *intf,
|
|||
__set_bit(EV_REL, input_dev->evbit);
|
||||
__set_bit(REL_X, input_dev->relbit);
|
||||
__set_bit(REL_Y, input_dev->relbit);
|
||||
__set_bit(INPUT_PROP_POINTING_STICK, input_dev->propbit);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0);
|
||||
} else {
|
||||
input_set_abs_params(input_dev, ABS_X,
|
||||
|
@ -401,6 +402,11 @@ static int synusb_probe(struct usb_interface *intf,
|
|||
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
|
||||
}
|
||||
|
||||
if (synusb->flags & SYNUSB_TOUCHSCREEN)
|
||||
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
||||
else
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
__set_bit(BTN_RIGHT, input_dev->keybit);
|
||||
__set_bit(BTN_MIDDLE, input_dev->keybit);
|
||||
|
|
|
@ -393,6 +393,9 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
|
|||
if ((button_info & 0x0f) >= 3)
|
||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, psmouse->dev->propbit);
|
||||
__set_bit(INPUT_PROP_POINTING_STICK, psmouse->dev->propbit);
|
||||
|
||||
trackpoint_defaults(psmouse->private);
|
||||
|
||||
error = trackpoint_power_on_reset(&psmouse->ps2dev);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Input device TTY line discipline");
|
||||
|
@ -198,29 +199,56 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void serport_set_type(struct tty_struct *tty, unsigned long type)
|
||||
{
|
||||
struct serport *serport = tty->disc_data;
|
||||
|
||||
serport->id.proto = type & 0x000000ff;
|
||||
serport->id.id = (type & 0x0000ff00) >> 8;
|
||||
serport->id.extra = (type & 0x00ff0000) >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* serport_ldisc_ioctl() allows to set the port protocol, and device ID
|
||||
*/
|
||||
|
||||
static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
|
||||
static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct serport *serport = (struct serport*) tty->disc_data;
|
||||
unsigned long type;
|
||||
|
||||
if (cmd == SPIOCSTYPE) {
|
||||
unsigned long type;
|
||||
|
||||
if (get_user(type, (unsigned long __user *) arg))
|
||||
return -EFAULT;
|
||||
|
||||
serport->id.proto = type & 0x000000ff;
|
||||
serport->id.id = (type & 0x0000ff00) >> 8;
|
||||
serport->id.extra = (type & 0x00ff0000) >> 16;
|
||||
|
||||
serport_set_type(tty, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t)
|
||||
static long serport_ldisc_compat_ioctl(struct tty_struct *tty,
|
||||
struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (cmd == COMPAT_SPIOCSTYPE) {
|
||||
void __user *uarg = compat_ptr(arg);
|
||||
compat_ulong_t compat_type;
|
||||
|
||||
if (get_user(compat_type, (compat_ulong_t __user *)uarg))
|
||||
return -EFAULT;
|
||||
|
||||
serport_set_type(tty, compat_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
|
||||
{
|
||||
struct serport *serport = (struct serport *) tty->disc_data;
|
||||
|
@ -243,6 +271,9 @@ static struct tty_ldisc_ops serport_ldisc = {
|
|||
.close = serport_ldisc_close,
|
||||
.read = serport_ldisc_read,
|
||||
.ioctl = serport_ldisc_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = serport_ldisc_compat_ioctl,
|
||||
#endif
|
||||
.receive_buf = serport_ldisc_receive,
|
||||
.write_wakeup = serport_ldisc_write_wakeup
|
||||
};
|
||||
|
|
|
@ -837,7 +837,12 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
|
|||
count = data->msg_buf[0];
|
||||
|
||||
if (count == 0) {
|
||||
dev_warn(dev, "Interrupt triggered but zero messages\n");
|
||||
/*
|
||||
* This condition is caused by the CHG line being configured
|
||||
* in Mode 0. It results in unnecessary I2C operations but it
|
||||
* is benign.
|
||||
*/
|
||||
dev_dbg(dev, "Interrupt triggered but zero messages\n");
|
||||
return IRQ_NONE;
|
||||
} else if (count > data->max_reportid) {
|
||||
dev_err(dev, "T44 count %d exceeded max report id\n", count);
|
||||
|
@ -1374,11 +1379,16 @@ static int mxt_get_info(struct mxt_data *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mxt_free_input_device(struct mxt_data *data)
|
||||
{
|
||||
if (data->input_dev) {
|
||||
input_unregister_device(data->input_dev);
|
||||
data->input_dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mxt_free_object_table(struct mxt_data *data)
|
||||
{
|
||||
input_unregister_device(data->input_dev);
|
||||
data->input_dev = NULL;
|
||||
|
||||
kfree(data->object_table);
|
||||
data->object_table = NULL;
|
||||
kfree(data->msg_buf);
|
||||
|
@ -1957,11 +1967,13 @@ static int mxt_load_fw(struct device *dev, const char *fn)
|
|||
ret = mxt_lookup_bootloader_address(data, 0);
|
||||
if (ret)
|
||||
goto release_firmware;
|
||||
|
||||
mxt_free_input_device(data);
|
||||
mxt_free_object_table(data);
|
||||
} else {
|
||||
enable_irq(data->irq);
|
||||
}
|
||||
|
||||
mxt_free_object_table(data);
|
||||
reinit_completion(&data->bl_completion);
|
||||
|
||||
ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
|
||||
|
@ -2210,6 +2222,7 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
return 0;
|
||||
|
||||
err_free_object:
|
||||
mxt_free_input_device(data);
|
||||
mxt_free_object_table(data);
|
||||
err_free_irq:
|
||||
free_irq(client->irq, data);
|
||||
|
@ -2224,7 +2237,7 @@ static int mxt_remove(struct i2c_client *client)
|
|||
|
||||
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
|
||||
free_irq(data->irq, data);
|
||||
input_unregister_device(data->input_dev);
|
||||
mxt_free_input_device(data);
|
||||
mxt_free_object_table(data);
|
||||
kfree(data);
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
*/
|
||||
static int rpu = 8;
|
||||
module_param(rpu, int, 0);
|
||||
MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
|
||||
MODULE_PARM_DESC(rpu, "Set internal pull up resistor for pen detect.");
|
||||
|
||||
/*
|
||||
* Set current used for pressure measurement.
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
*/
|
||||
static int rpu = 8;
|
||||
module_param(rpu, int, 0);
|
||||
MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
|
||||
MODULE_PARM_DESC(rpu, "Set internal pull up resistor for pen detect.");
|
||||
|
||||
/*
|
||||
* Set current used for pressure measurement.
|
||||
|
|
|
@ -165,6 +165,7 @@ struct input_keymap_entry {
|
|||
#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */
|
||||
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
|
||||
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
|
||||
#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */
|
||||
|
||||
#define INPUT_PROP_MAX 0x1f
|
||||
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
|
||||
|
|
Loading…
Reference in a new issue