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_CONFIG 0x22
|
||||||
#define CAP1106_REG_SENSOR_CONFIG2 0x23
|
#define CAP1106_REG_SENSOR_CONFIG2 0x23
|
||||||
#define CAP1106_REG_SAMPLING_CONFIG 0x24
|
#define CAP1106_REG_SAMPLING_CONFIG 0x24
|
||||||
#define CAP1106_REG_CALIBRATION 0x25
|
#define CAP1106_REG_CALIBRATION 0x26
|
||||||
#define CAP1106_REG_INT_ENABLE 0x26
|
#define CAP1106_REG_INT_ENABLE 0x27
|
||||||
#define CAP1106_REG_REPEAT_RATE 0x28
|
#define CAP1106_REG_REPEAT_RATE 0x28
|
||||||
#define CAP1106_REG_MT_CONFIG 0x2a
|
#define CAP1106_REG_MT_CONFIG 0x2a
|
||||||
#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b
|
#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) {
|
if (pdata->clustered_irq > 0) {
|
||||||
err = request_irq(pdata->clustered_irq,
|
err = request_any_context_irq(pdata->clustered_irq,
|
||||||
matrix_keypad_interrupt,
|
matrix_keypad_interrupt,
|
||||||
pdata->clustered_irq_flags,
|
pdata->clustered_irq_flags,
|
||||||
"matrix-keypad", keypad);
|
"matrix-keypad", keypad);
|
||||||
if (err) {
|
if (err < 0) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Unable to acquire clustered interrupt\n");
|
"Unable to acquire clustered interrupt\n");
|
||||||
goto err_free_rows;
|
goto err_free_rows;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < pdata->num_row_gpios; i++) {
|
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,
|
matrix_keypad_interrupt,
|
||||||
IRQF_TRIGGER_RISING |
|
IRQF_TRIGGER_RISING |
|
||||||
IRQF_TRIGGER_FALLING,
|
IRQF_TRIGGER_FALLING,
|
||||||
"matrix-keypad", keypad);
|
"matrix-keypad", keypad);
|
||||||
if (err) {
|
if (err < 0) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Unable to acquire interrupt for GPIO line %i\n",
|
"Unable to acquire interrupt for GPIO line %i\n",
|
||||||
pdata->row_gpios[i]);
|
pdata->row_gpios[i]);
|
||||||
|
|
|
@ -2373,6 +2373,10 @@ int alps_init(struct psmouse *psmouse)
|
||||||
dev2->keybit[BIT_WORD(BTN_LEFT)] =
|
dev2->keybit[BIT_WORD(BTN_LEFT)] =
|
||||||
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
|
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))
|
if (input_register_device(priv->dev2))
|
||||||
goto init_fail;
|
goto init_fail;
|
||||||
|
|
||||||
|
|
|
@ -1331,6 +1331,13 @@ static bool elantech_is_signature_valid(const unsigned char *param)
|
||||||
if (param[1] == 0)
|
if (param[1] == 0)
|
||||||
return true;
|
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++)
|
for (i = 0; i < ARRAY_SIZE(rates); i++)
|
||||||
if (param[2] == rates[i])
|
if (param[2] == rates[i])
|
||||||
return false;
|
return false;
|
||||||
|
@ -1607,6 +1614,10 @@ int elantech_init(struct psmouse *psmouse)
|
||||||
tp_dev->keybit[BIT_WORD(BTN_LEFT)] =
|
tp_dev->keybit[BIT_WORD(BTN_LEFT)] =
|
||||||
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
|
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
|
||||||
BIT_MASK(BTN_RIGHT);
|
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);
|
error = input_register_device(etd->tp_dev);
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
goto init_fail_tp_reg;
|
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_X, input_dev->relbit);
|
||||||
__set_bit(REL_Y, 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_rate = psmouse_set_rate;
|
||||||
psmouse->set_resolution = psmouse_set_resolution;
|
psmouse->set_resolution = psmouse_set_resolution;
|
||||||
psmouse->poll = psmouse_poll;
|
psmouse->poll = psmouse_poll;
|
||||||
|
|
|
@ -629,10 +629,61 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
||||||
((buf[0] & 0x04) >> 1) |
|
((buf[0] & 0x04) >> 1) |
|
||||||
((buf[3] & 0x04) >> 2));
|
((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->left = (buf[0] & 0x01) ? 1 : 0;
|
||||||
hw->right = (buf[0] & 0x02) ? 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,
|
* Clickpad's button is transmitted as middle button,
|
||||||
* however, since it is primary button, we will report
|
* 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;
|
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) &&
|
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
|
||||||
((buf[0] ^ buf[3]) & 0x02)) {
|
((buf[0] ^ buf[3]) & 0x02)) {
|
||||||
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
|
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
|
* 2 0x08 image sensor image sensor tracks 5 fingers, but only
|
||||||
* reports 2.
|
* reports 2.
|
||||||
* 2 0x20 report min query 0x0f gives min coord reported
|
* 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_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */
|
||||||
#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-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_ADV_GESTURE(ex0c) ((ex0c) & 0x080000)
|
||||||
#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
|
#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400)
|
||||||
#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800)
|
#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800)
|
||||||
|
#define SYN_CAP_FORCEPAD(ex0c) ((ex0c) & 0x008000)
|
||||||
|
|
||||||
/* synaptics modes query bits */
|
/* synaptics modes query bits */
|
||||||
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
|
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
|
||||||
|
@ -177,6 +183,11 @@ struct synaptics_data {
|
||||||
*/
|
*/
|
||||||
struct synaptics_hw_state agm;
|
struct synaptics_hw_state agm;
|
||||||
bool agm_pending; /* new AGM packet received */
|
bool agm_pending; /* new AGM packet received */
|
||||||
|
|
||||||
|
/* ForcePad handling */
|
||||||
|
unsigned long press_start;
|
||||||
|
bool press;
|
||||||
|
bool report_press;
|
||||||
};
|
};
|
||||||
|
|
||||||
void synaptics_module_init(void);
|
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(EV_REL, input_dev->evbit);
|
||||||
__set_bit(REL_X, input_dev->relbit);
|
__set_bit(REL_X, input_dev->relbit);
|
||||||
__set_bit(REL_Y, 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);
|
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
input_set_abs_params(input_dev, ABS_X,
|
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);
|
__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_LEFT, input_dev->keybit);
|
||||||
__set_bit(BTN_RIGHT, input_dev->keybit);
|
__set_bit(BTN_RIGHT, input_dev->keybit);
|
||||||
__set_bit(BTN_MIDDLE, 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)
|
if ((button_info & 0x0f) >= 3)
|
||||||
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
|
__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);
|
trackpoint_defaults(psmouse->private);
|
||||||
|
|
||||||
error = trackpoint_power_on_reset(&psmouse->ps2dev);
|
error = trackpoint_power_on_reset(&psmouse->ps2dev);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/serio.h>
|
#include <linux/serio.h>
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||||
MODULE_DESCRIPTION("Input device TTY line discipline");
|
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;
|
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
|
* 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) {
|
if (cmd == SPIOCSTYPE) {
|
||||||
|
unsigned long type;
|
||||||
|
|
||||||
if (get_user(type, (unsigned long __user *) arg))
|
if (get_user(type, (unsigned long __user *) arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
serport->id.proto = type & 0x000000ff;
|
serport_set_type(tty, type);
|
||||||
serport->id.id = (type & 0x0000ff00) >> 8;
|
|
||||||
serport->id.extra = (type & 0x00ff0000) >> 16;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
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)
|
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
|
||||||
{
|
{
|
||||||
struct serport *serport = (struct serport *) tty->disc_data;
|
struct serport *serport = (struct serport *) tty->disc_data;
|
||||||
|
@ -243,6 +271,9 @@ static struct tty_ldisc_ops serport_ldisc = {
|
||||||
.close = serport_ldisc_close,
|
.close = serport_ldisc_close,
|
||||||
.read = serport_ldisc_read,
|
.read = serport_ldisc_read,
|
||||||
.ioctl = serport_ldisc_ioctl,
|
.ioctl = serport_ldisc_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = serport_ldisc_compat_ioctl,
|
||||||
|
#endif
|
||||||
.receive_buf = serport_ldisc_receive,
|
.receive_buf = serport_ldisc_receive,
|
||||||
.write_wakeup = serport_ldisc_write_wakeup
|
.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];
|
count = data->msg_buf[0];
|
||||||
|
|
||||||
if (count == 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;
|
return IRQ_NONE;
|
||||||
} else if (count > data->max_reportid) {
|
} else if (count > data->max_reportid) {
|
||||||
dev_err(dev, "T44 count %d exceeded max report id\n", count);
|
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;
|
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)
|
static void mxt_free_object_table(struct mxt_data *data)
|
||||||
{
|
{
|
||||||
input_unregister_device(data->input_dev);
|
|
||||||
data->input_dev = NULL;
|
|
||||||
|
|
||||||
kfree(data->object_table);
|
kfree(data->object_table);
|
||||||
data->object_table = NULL;
|
data->object_table = NULL;
|
||||||
kfree(data->msg_buf);
|
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);
|
ret = mxt_lookup_bootloader_address(data, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto release_firmware;
|
goto release_firmware;
|
||||||
|
|
||||||
|
mxt_free_input_device(data);
|
||||||
|
mxt_free_object_table(data);
|
||||||
} else {
|
} else {
|
||||||
enable_irq(data->irq);
|
enable_irq(data->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
mxt_free_object_table(data);
|
|
||||||
reinit_completion(&data->bl_completion);
|
reinit_completion(&data->bl_completion);
|
||||||
|
|
||||||
ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
|
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;
|
return 0;
|
||||||
|
|
||||||
err_free_object:
|
err_free_object:
|
||||||
|
mxt_free_input_device(data);
|
||||||
mxt_free_object_table(data);
|
mxt_free_object_table(data);
|
||||||
err_free_irq:
|
err_free_irq:
|
||||||
free_irq(client->irq, data);
|
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);
|
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
|
||||||
free_irq(data->irq, data);
|
free_irq(data->irq, data);
|
||||||
input_unregister_device(data->input_dev);
|
mxt_free_input_device(data);
|
||||||
mxt_free_object_table(data);
|
mxt_free_object_table(data);
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
*/
|
*/
|
||||||
static int rpu = 8;
|
static int rpu = 8;
|
||||||
module_param(rpu, int, 0);
|
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.
|
* Set current used for pressure measurement.
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
*/
|
*/
|
||||||
static int rpu = 8;
|
static int rpu = 8;
|
||||||
module_param(rpu, int, 0);
|
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.
|
* 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_BUTTONPAD 0x02 /* has button(s) under pad */
|
||||||
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
|
#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */
|
||||||
#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */
|
#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_MAX 0x1f
|
||||||
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
|
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
|
||||||
|
|
Loading…
Reference in a new issue