Commit 1c5ff2ab authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:
 - new driver for eGalaxTouch serial touchscreen
 - new driver for TS-4800 touchscreen
 - an update for Goodix touchscreen driver
 - PS/2 mouse module was reworked to limit number of protocols we try on
   pass-through ports to speed up their detection time
 - wacom_w8001 touchscreen driver now reports pen and touch via separate
   instances of input devices
 - other driver changes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (42 commits)
  Input: elantech - mark protocols v2 and v3 as semi-mt
  Input: wacom_w8001 - drop use of ABS_MT_TOOL_TYPE
  Input: gpio-keys - fix check for disabling unsupported keys
  Input: omap-keypad - remove dead check
  Input: ti_am335x_tsc - fix HWPEN interrupt handling
  Input: omap-keypad - set tasklet data earlier
  Input: rohm_bu21023 - fix handling of retrying firmware update
  Input: ALPS - report v3 pinnacle trackstick device only if is present
  Input: ALPS - detect trackstick presence for v7 protocol
  Input: pcap_ts - use to_delayed_work
  Input: bma150 - constify bma150_cfg structure
  Input: i8042 - add Fujitsu Lifebook U745 to the nomux list
  Input: egalax_ts_serial - fix potential NULL dereference on error
  Input: uinput - sanity check on ff_effects_max and EV_FF
  Input: uinput - rework ABS validation
  Input: uinput - add new UINPUT_DEV_SETUP and UI_ABS_SETUP ioctl
  Input: goodix - use "inverted_[xy]" flags instead of "rotated_screen"
  Input: goodix - add axis swapping and axis inversion support
  Input: goodix - use goodix_i2c_write_u8 instead of i2c_master_send
  Input: goodix - add power management support
  ...
parents d6a32277 009f7738
......@@ -13,6 +13,17 @@ Required properties:
- interrupt-parent : Interrupt controller to which the chip is connected
- interrupts : Interrupt to which the chip is connected
Optional properties:
- irq-gpios : GPIO pin used for IRQ. The driver uses the
interrupt gpio pin as output to reset the device.
- reset-gpios : GPIO pin used for reset
- touchscreen-inverted-x : X axis is inverted (boolean)
- touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
(swapping is done after inverting the axis)
Example:
i2c@00000000 {
......@@ -23,6 +34,9 @@ Example:
reg = <0x5d>;
interrupt-parent = <&gpio>;
interrupts = <0 0>;
irq-gpios = <&gpio1 0 0>;
reset-gpios = <&gpio1 1 0>;
};
/* ... */
......
......@@ -9,7 +9,9 @@ Required properties:
- touchscreen-size-y: vertical resolution of touchscreen (in pixels)
Optional properties:
- reset-gpio: GPIO connected to the RESET line of the chip
- reset-gpios: GPIO connected to the RESET line of the chip
- enable-gpios: GPIO connected to the ENABLE line of the chip
- wake-gpios: GPIO connected to the WAKE line of the chip
Example:
......
* TS-4800 Touchscreen bindings
Required properties:
- compatible: must be "technologic,ts4800-ts"
- reg: physical base address of the controller and length of memory mapped
region.
- syscon: phandle / integers array that points to the syscon node which
describes the FPGA's syscon registers.
- phandle to FPGA's syscon
- offset to the touchscreen register
- offset to the touchscreen enable bit
......@@ -943,3 +943,46 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
}
return count;
}
struct acpi_crs_lookup {
struct list_head node;
struct acpi_device *adev;
const char *con_id;
};
static DEFINE_MUTEX(acpi_crs_lookup_lock);
static LIST_HEAD(acpi_crs_lookup_list);
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
{
struct acpi_crs_lookup *l, *lookup = NULL;
/* Never allow fallback if the device has properties */
if (adev->data.properties || adev->driver_gpios)
return false;
mutex_lock(&acpi_crs_lookup_lock);
list_for_each_entry(l, &acpi_crs_lookup_list, node) {
if (l->adev == adev) {
lookup = l;
break;
}
}
if (!lookup) {
lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
if (lookup) {
lookup->adev = adev;
lookup->con_id = con_id;
list_add_tail(&lookup->node, &acpi_crs_lookup_list);
}
}
mutex_unlock(&acpi_crs_lookup_lock);
return lookup &&
((!lookup->con_id && !con_id) ||
(lookup->con_id && con_id &&
strcmp(lookup->con_id, con_id) == 0));
}
......@@ -1874,6 +1874,9 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
if (!acpi_can_fallback_to_crs(adev, con_id))
return ERR_PTR(-ENOENT);
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
if (IS_ERR(desc))
return desc;
......
......@@ -48,6 +48,8 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
struct acpi_gpio_info *info);
int acpi_gpio_count(struct device *dev, const char *con_id);
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
......@@ -74,6 +76,12 @@ static inline int acpi_gpio_count(struct device *dev, const char *con_id)
{
return -ENODEV;
}
static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
const char *con_id)
{
return false;
}
#endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
......
......@@ -96,13 +96,29 @@ struct gpio_keys_drvdata {
* Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type.
*/
static inline int get_n_events_by_type(int type)
static int get_n_events_by_type(int type)
{
BUG_ON(type != EV_SW && type != EV_KEY);
return (type == EV_KEY) ? KEY_CNT : SW_CNT;
}
/**
* get_bm_events_by_type() - returns bitmap of supported events per @type
* @input: input device from which bitmap is retrieved
* @type: type of button (%EV_KEY, %EV_SW)
*
* Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type.
*/
static const unsigned long *get_bm_events_by_type(struct input_dev *dev,
int type)
{
BUG_ON(type != EV_SW && type != EV_KEY);
return (type == EV_KEY) ? dev->keybit : dev->swbit;
}
/**
* gpio_keys_disable_button() - disables given GPIO button
* @bdata: button data for button to be disabled
......@@ -213,6 +229,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
const char *buf, unsigned int type)
{
int n_events = get_n_events_by_type(type);
const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
unsigned long *bits;
ssize_t error;
int i;
......@@ -226,6 +243,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
goto out;
/* First validate */
if (!bitmap_subset(bits, bitmap, n_events)) {
error = -EINVAL;
goto out;
}
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
......@@ -239,11 +261,6 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
}
}
if (i == ddata->pdata->nbuttons) {
error = -EINVAL;
goto out;
}
mutex_lock(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) {
......
......@@ -155,14 +155,6 @@ static void omap_kp_tasklet(unsigned long data)
"pressed" : "released");
#else
key = keycodes[MATRIX_SCAN_CODE(row, col, row_shift)];
if (key < 0) {
printk(KERN_WARNING
"omap-keypad: Spurious key event %d-%d\n",
col, row);
/* We scan again after a couple of seconds */
spurious = 1;
continue;
}
if (!(kp_cur_group == (key & GROUP_MASK) ||
kp_cur_group == -1))
......@@ -292,8 +284,8 @@ static int omap_kp_probe(struct platform_device *pdev)
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
/* get the irq and init timer*/
tasklet_enable(&kp_tasklet);
kp_tasklet.data = (unsigned long) omap_kp;
tasklet_enable(&kp_tasklet);
ret = device_create_file(&pdev->dev, &dev_attr_enable);
if (ret < 0)
......
......@@ -147,7 +147,7 @@ struct bma150_data {
* are stated and verified by Bosch Sensortec where they are configured
* to provide a generic sensitivity performance.
*/
static struct bma150_cfg default_cfg = {
static const struct bma150_cfg default_cfg = {
.any_motion_int = 1,
.hg_int = 1,
.lg_int = 1,
......
......@@ -179,13 +179,13 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input);
schedule_delayed_work(&onkey->work, 0);
dev_dbg(onkey->dev, "KEY_POWER pressed.\n");
dev_dbg(onkey->dev, "KEY_POWER long press.\n");
} else {
input_report_key(onkey->input, KEY_SLEEP, 1);
input_report_key(onkey->input, KEY_POWER, 1);
input_sync(onkey->input);
input_report_key(onkey->input, KEY_SLEEP, 0);
input_report_key(onkey->input, KEY_POWER, 0);
input_sync(onkey->input);
dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n");
dev_dbg(onkey->dev, "KEY_POWER short press.\n");
}
return IRQ_HANDLED;
......
......@@ -345,23 +345,19 @@ static struct platform_driver grover_beep_driver = {
.shutdown = sparcspkr_shutdown,
};
static struct platform_driver * const drivers[] = {
&bbc_beep_driver,
&grover_beep_driver,
};
static int __init sparcspkr_init(void)
{
int err = platform_driver_register(&bbc_beep_driver);
if (!err) {
err = platform_driver_register(&grover_beep_driver);
if (err)
platform_driver_unregister(&bbc_beep_driver);
}
return err;
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
static void __exit sparcspkr_exit(void)
{
platform_driver_unregister(&bbc_beep_driver);
platform_driver_unregister(&grover_beep_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(sparcspkr_init);
......
......@@ -256,13 +256,29 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev)
{
struct input_dev *dev = udev->dev;
int error;
int error, nslot;
if (udev->state != UIST_SETUP_COMPLETE) {
printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
return -EINVAL;
}
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
error = input_mt_init_slots(dev, nslot, 0);
if (error)
goto fail1;
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) {
printk(KERN_DEBUG "%s: ff_effects_max should be non-zero when FF_BIT is set\n",
UINPUT_NAME);
error = -EINVAL;
goto fail1;
}
if (udev->ff_effects_max) {
error = input_ff_create(dev, udev->ff_effects_max);
if (error)
......@@ -308,10 +324,35 @@ static int uinput_open(struct inode *inode, struct file *file)
return 0;
}
static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
const struct input_absinfo *abs)
{
int min, max;
min = abs->minimum;
max = abs->maximum;
if ((min != 0 || max != 0) && max <= min) {
printk(KERN_DEBUG
"%s: invalid abs[%02x] min:%d max:%d\n",
UINPUT_NAME, code, min, max);
return -EINVAL;
}
if (abs->flat > max - min) {
printk(KERN_DEBUG
"%s: abs_flat #%02x out of range: %d (min:%d/max:%d)\n",
UINPUT_NAME, code, abs->flat, min, max);
return -EINVAL;
}
return 0;
}
static int uinput_validate_absbits(struct input_dev *dev)
{
unsigned int cnt;
int nslot;
int error;
if (!test_bit(EV_ABS, dev->evbit))
return 0;
......@@ -321,38 +362,12 @@ static int uinput_validate_absbits(struct input_dev *dev)
*/
for_each_set_bit(cnt, dev->absbit, ABS_CNT) {
int min, max;
min = input_abs_get_min(dev, cnt);
max = input_abs_get_max(dev, cnt);
if ((min != 0 || max != 0) && max <= min) {
printk(KERN_DEBUG
"%s: invalid abs[%02x] min:%d max:%d\n",
UINPUT_NAME, cnt,
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
if (!dev->absinfo)
return -EINVAL;
}
if (input_abs_get_flat(dev, cnt) >
input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) {
printk(KERN_DEBUG
"%s: abs_flat #%02x out of range: %d "
"(min:%d/max:%d)\n",
UINPUT_NAME, cnt,
input_abs_get_flat(dev, cnt),
input_abs_get_min(dev, cnt),
input_abs_get_max(dev, cnt));
return -EINVAL;
}
}
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
input_mt_init_slots(dev, nslot, 0);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
error = uinput_validate_absinfo(dev, cnt, &dev->absinfo[cnt]);
if (error)
return error;
}
return 0;
......@@ -370,8 +385,71 @@ static int uinput_allocate_device(struct uinput_device *udev)
return 0;
}
static int uinput_setup_device(struct uinput_device *udev,
const char __user *buffer, size_t count)
static int uinput_dev_setup(struct uinput_device *udev,
struct uinput_setup __user *arg)
{
struct uinput_setup setup;
struct input_dev *dev;
if (udev->state == UIST_CREATED)
return -EINVAL;
if (copy_from_user(&setup, arg, sizeof(setup)))
return -EFAULT;
if (!setup.name[0])
return -EINVAL;
dev = udev->dev;
dev->id = setup.id;
udev->ff_effects_max = setup.ff_effects_max;
kfree(dev->name);
dev->name = kstrndup(setup.name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL);
if (!dev->name)
return -ENOMEM;
udev->state = UIST_SETUP_COMPLETE;
return 0;
}
static int uinput_abs_setup(struct uinput_device *udev,
struct uinput_setup __user *arg, size_t size)
{
struct uinput_abs_setup setup = {};
struct input_dev *dev;
int error;
if (size > sizeof(setup))
return -E2BIG;
if (udev->state == UIST_CREATED)
return -EINVAL;
if (copy_from_user(&setup, arg, size))
return -EFAULT;
if (setup.code > ABS_MAX)
return -ERANGE;
dev = udev->dev;
error = uinput_validate_absinfo(dev, setup.code, &setup.absinfo);
if (error)
return error;
input_alloc_absinfo(dev);
if (!dev->absinfo)
return -ENOMEM;
set_bit(setup.code, dev->absbit);
dev->absinfo[setup.code] = setup.absinfo;
return 0;
}
/* legacy setup via write() */
static int uinput_setup_device_legacy(struct uinput_device *udev,
const char __user *buffer, size_t count)
{
struct uinput_user_dev *user_dev;
struct input_dev *dev;
......@@ -474,7 +552,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
retval = udev->state == UIST_CREATED ?
uinput_inject_events(udev, buffer, count) :
uinput_setup_device(udev, buffer, count);
uinput_setup_device_legacy(udev, buffer, count);
mutex_unlock(&udev->mutex);
......@@ -735,6 +813,12 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
uinput_destroy_device(udev);
goto out;
case UI_DEV_SETUP:
retval = uinput_dev_setup(udev, p);
goto out;
/* UI_ABS_SETUP is handled in the variable size ioctls */
case UI_SET_EVBIT:
retval = uinput_set_bit(arg, evbit, EV_MAX);
goto out;
......@@ -879,6 +963,10 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
name = dev_name(&udev->dev->dev);
retval = uinput_str_to_user(p, name, size);
goto out;
case UI_ABS_SETUP & ~IOCSIZE_MASK:
retval = uinput_abs_setup(udev, p, size);
goto out;
}
retval = -EINVAL;
......
......@@ -31,6 +31,7 @@
#define ALPS_CMD_NIBBLE_10 0x01f2
#define ALPS_REG_BASE_RUSHMORE 0xc2c0
#define ALPS_REG_BASE_V7 0xc2c0
#define ALPS_REG_BASE_PINNACLE 0x0000
static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
......@@ -2047,7 +2048,7 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
return 0;
}
static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base)
static int alps_probe_trackstick_v3_v7(struct psmouse *psmouse, int reg_base)
{
int ret = -EIO, reg_val;
......@@ -2128,15 +2129,12 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
static int alps_hw_init_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
struct ps2dev *ps2dev = &psmouse->ps2dev;
int reg_val;
unsigned char param[4];
reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE);
if (reg_val == -EIO)
goto error;
if (reg_val == 0 &&
if ((priv->flags & ALPS_DUALPOINT) &&
alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
goto error;
......@@ -2613,6 +2611,11 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->decode_fields = alps_decode_pinnacle;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_PINNACLE) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break;
case ALPS_PROTO_V3_RUSHMORE:
......@@ -2625,8 +2628,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
priv->x_bits = 16;
priv->y_bits = 12;
if (alps_probe_trackstick_v3(psmouse,
ALPS_REG_BASE_RUSHMORE) < 0)
if (alps_probe_trackstick_v3_v7(psmouse,
ALPS_REG_BASE_RUSHMORE) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break;
......@@ -2676,6 +2679,9 @@ static int alps_set_protocol(struct psmouse *psmouse,
if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD;
if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0)
priv->flags &= ~ALPS_DUALPOINT;
break;
case ALPS_PROTO_V8:
......
......@@ -1222,7 +1222,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
ETP_WMAX_V2, 0, 0);
}
input_mt_init_slots(dev, 2, 0);
input_mt_init_slots(dev, 2, INPUT_MT_SEMI_MT);
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
break;
......
......@@ -49,12 +49,6 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties)
return 0;
}
static void focaltech_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
}
#ifdef CONFIG_MOUSE_PS2_FOCALTECH
/*
......@@ -300,6 +294,12 @@ static int focaltech_switch_protocol(struct psmouse *psmouse)
return 0;
}
static void focaltech_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
}
static void focaltech_disconnect(struct psmouse *psmouse)
{
focaltech_reset(psmouse);
......@@ -456,14 +456,4 @@ int focaltech_init(struct psmouse *psmouse)
kfree(priv);
return error;
}
#else /* CONFIG_MOUSE_PS2_FOCALTECH */
int focaltech_init(struct psmouse *psmouse)
{
focaltech_reset(psmouse);
return 0;
}
#endif /* CONFIG_MOUSE_PS2_FOCALTECH */
......@@ -18,6 +18,14 @@
#define _FOCALTECH_H
int focaltech_detect(struct psmouse *psmouse, bool set_properties);
#ifdef CONFIG_MOUSE_PS2_FOCALTECH
int focaltech_init(struct psmouse *psmouse);
#else
static inline int focaltech_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
#endif
#endif
......@@ -325,7 +325,7 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse,
* that support it.
*/
int ps2pp_init(struct psmouse *psmouse, bool set_properties)
int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
......
......@@ -12,9 +12,9 @@
#define _LOGIPS2PP_H
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
int ps2pp_init(struct psmouse *psmouse, bool set_properties);
int ps2pp_detect(struct psmouse *psmouse, bool set_properties);
#else
inline int ps2pp_init(struct psmouse *psmouse, bool set_properties)
static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}
......
This diff is collapsed.
......@@ -257,6 +257,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"),
},
},
{
/* Fujitsu Lifebook U745 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
},
},
{
/* Fujitsu T70H */
.matches = {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment