diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-21 15:54:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-21 15:54:08 -0400 |
commit | b8ce8d7222b52200e61ea29523993e20751baaaa (patch) | |
tree | 323b47725de6726121aa78f98a88738105ee8202 /drivers/input | |
parent | 1d11437f4fd02f9b5d3749675a1232216787dcc6 (diff) | |
parent | 48853389f206b689260ddfd3006816779ca7a52a (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull more input subsystem updates from Dmitry Torokhov:
- an update to Atmel MXT driver that makes it functional on Google
Pixel 2 boxes (both touchpad and touchscreen)
- a new VMware VMMouse driver that should allow us drop X vmmouse
driver that requires root privileges (since it accesses ioports)
- XBox One controllers now support force feedback (rumble)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
Input: lm8333 - fix broken email address
Input: cyapa - fix setting suspend scan rate
Input: elan_i2c - fix calculating number of x and y traces.
Input: elan_i2c - report hovering contacts
Input: elants_i2c - zero-extend hardware ID in firmware name
Input: alps - document separate pointstick button bits for V2 devices
Input: atmel_mxt_ts - add support for Google Pixel 2
Input: xpad - add rumble support for Xbox One controller
Input: ff-core - use new debug macros
Input: add vmmouse driver
Input: elan_i2c - adjust for newer firmware pressure reporting
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/ff-core.c | 10 | ||||
-rw-r--r-- | drivers/input/joystick/xpad.c | 21 | ||||
-rw-r--r-- | drivers/input/keyboard/lm8333.c | 4 | ||||
-rw-r--r-- | drivers/input/mouse/Kconfig | 12 | ||||
-rw-r--r-- | drivers/input/mouse/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/mouse/cyapa.c | 4 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c.h | 3 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_core.c | 38 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_i2c.c | 27 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_smbus.c | 12 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 17 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse.h | 1 | ||||
-rw-r--r-- | drivers/input/mouse/vmmouse.c | 508 | ||||
-rw-r--r-- | drivers/input/mouse/vmmouse.h | 30 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 141 | ||||
-rw-r--r-- | drivers/input/touchscreen/elants_i2c.c | 2 |
16 files changed, 791 insertions, 40 deletions
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index f50f6dd92274..b81c88c43452 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c | |||
@@ -23,8 +23,6 @@ | |||
23 | 23 | ||
24 | /* #define DEBUG */ | 24 | /* #define DEBUG */ |
25 | 25 | ||
26 | #define pr_fmt(fmt) KBUILD_BASENAME ": " fmt | ||
27 | |||
28 | #include <linux/input.h> | 26 | #include <linux/input.h> |
29 | #include <linux/module.h> | 27 | #include <linux/module.h> |
30 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
@@ -116,7 +114,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, | |||
116 | 114 | ||
117 | if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || | 115 | if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || |
118 | !test_bit(effect->type, dev->ffbit)) { | 116 | !test_bit(effect->type, dev->ffbit)) { |
119 | pr_debug("invalid or not supported effect type in upload\n"); | 117 | dev_dbg(&dev->dev, "invalid or not supported effect type in upload\n"); |
120 | return -EINVAL; | 118 | return -EINVAL; |
121 | } | 119 | } |
122 | 120 | ||
@@ -124,7 +122,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, | |||
124 | (effect->u.periodic.waveform < FF_WAVEFORM_MIN || | 122 | (effect->u.periodic.waveform < FF_WAVEFORM_MIN || |
125 | effect->u.periodic.waveform > FF_WAVEFORM_MAX || | 123 | effect->u.periodic.waveform > FF_WAVEFORM_MAX || |
126 | !test_bit(effect->u.periodic.waveform, dev->ffbit))) { | 124 | !test_bit(effect->u.periodic.waveform, dev->ffbit))) { |
127 | pr_debug("invalid or not supported wave form in upload\n"); | 125 | dev_dbg(&dev->dev, "invalid or not supported wave form in upload\n"); |
128 | return -EINVAL; | 126 | return -EINVAL; |
129 | } | 127 | } |
130 | 128 | ||
@@ -246,7 +244,7 @@ static int flush_effects(struct input_dev *dev, struct file *file) | |||
246 | struct ff_device *ff = dev->ff; | 244 | struct ff_device *ff = dev->ff; |
247 | int i; | 245 | int i; |
248 | 246 | ||
249 | pr_debug("flushing now\n"); | 247 | dev_dbg(&dev->dev, "flushing now\n"); |
250 | 248 | ||
251 | mutex_lock(&ff->mutex); | 249 | mutex_lock(&ff->mutex); |
252 | 250 | ||
@@ -316,7 +314,7 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects) | |||
316 | int i; | 314 | int i; |
317 | 315 | ||
318 | if (!max_effects) { | 316 | if (!max_effects) { |
319 | pr_err("cannot allocate device without any effects\n"); | 317 | dev_err(&dev->dev, "cannot allocate device without any effects\n"); |
320 | return -EINVAL; | 318 | return -EINVAL; |
321 | } | 319 | } |
322 | 320 | ||
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 3aa2f3f3da5b..61c761156371 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
@@ -31,12 +31,14 @@ | |||
31 | * - the iForce driver drivers/char/joystick/iforce.c | 31 | * - the iForce driver drivers/char/joystick/iforce.c |
32 | * - the skeleton-driver drivers/usb/usb-skeleton.c | 32 | * - the skeleton-driver drivers/usb/usb-skeleton.c |
33 | * - Xbox 360 information http://www.free60.org/wiki/Gamepad | 33 | * - Xbox 360 information http://www.free60.org/wiki/Gamepad |
34 | * - Xbox One information https://github.com/quantus/xbox-one-controller-protocol | ||
34 | * | 35 | * |
35 | * Thanks to: | 36 | * Thanks to: |
36 | * - ITO Takayuki for providing essential xpad information on his website | 37 | * - ITO Takayuki for providing essential xpad information on his website |
37 | * - Vojtech Pavlik - iforce driver / input subsystem | 38 | * - Vojtech Pavlik - iforce driver / input subsystem |
38 | * - Greg Kroah-Hartman - usb-skeleton driver | 39 | * - Greg Kroah-Hartman - usb-skeleton driver |
39 | * - XBOX Linux project - extra USB id's | 40 | * - XBOX Linux project - extra USB id's |
41 | * - Pekka Pöyry (quantus) - Xbox One controller reverse engineering | ||
40 | * | 42 | * |
41 | * TODO: | 43 | * TODO: |
42 | * - fine tune axes (especially trigger axes) | 44 | * - fine tune axes (especially trigger axes) |
@@ -828,6 +830,23 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect | |||
828 | 830 | ||
829 | return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); | 831 | return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); |
830 | 832 | ||
833 | case XTYPE_XBOXONE: | ||
834 | xpad->odata[0] = 0x09; /* activate rumble */ | ||
835 | xpad->odata[1] = 0x08; | ||
836 | xpad->odata[2] = 0x00; | ||
837 | xpad->odata[3] = 0x08; /* continuous effect */ | ||
838 | xpad->odata[4] = 0x00; /* simple rumble mode */ | ||
839 | xpad->odata[5] = 0x03; /* L and R actuator only */ | ||
840 | xpad->odata[6] = 0x00; /* TODO: LT actuator */ | ||
841 | xpad->odata[7] = 0x00; /* TODO: RT actuator */ | ||
842 | xpad->odata[8] = strong / 256; /* left actuator */ | ||
843 | xpad->odata[9] = weak / 256; /* right actuator */ | ||
844 | xpad->odata[10] = 0x80; /* length of pulse */ | ||
845 | xpad->odata[11] = 0x00; /* stop period of pulse */ | ||
846 | xpad->irq_out->transfer_buffer_length = 12; | ||
847 | |||
848 | return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); | ||
849 | |||
831 | default: | 850 | default: |
832 | dev_dbg(&xpad->dev->dev, | 851 | dev_dbg(&xpad->dev->dev, |
833 | "%s - rumble command sent to unsupported xpad type: %d\n", | 852 | "%s - rumble command sent to unsupported xpad type: %d\n", |
@@ -841,7 +860,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect | |||
841 | 860 | ||
842 | static int xpad_init_ff(struct usb_xpad *xpad) | 861 | static int xpad_init_ff(struct usb_xpad *xpad) |
843 | { | 862 | { |
844 | if (xpad->xtype == XTYPE_UNKNOWN || xpad->xtype == XTYPE_XBOXONE) | 863 | if (xpad->xtype == XTYPE_UNKNOWN) |
845 | return 0; | 864 | return 0; |
846 | 865 | ||
847 | input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); | 866 | input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); |
diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 9081cbef11ea..0ad422b8a260 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * LM8333 keypad driver | 2 | * LM8333 keypad driver |
3 | * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de> | 3 | * Copyright (C) 2012 Wolfram Sang, Pengutronix <kernel@pengutronix.de> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -231,6 +231,6 @@ static struct i2c_driver lm8333_driver = { | |||
231 | }; | 231 | }; |
232 | module_i2c_driver(lm8333_driver); | 232 | module_i2c_driver(lm8333_driver); |
233 | 233 | ||
234 | MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); | 234 | MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>"); |
235 | MODULE_DESCRIPTION("LM8333 keyboard driver"); | 235 | MODULE_DESCRIPTION("LM8333 keyboard driver"); |
236 | MODULE_LICENSE("GPL v2"); | 236 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 4658b5d41dd7..7462d2fc8cfe 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
@@ -149,6 +149,18 @@ config MOUSE_PS2_FOCALTECH | |||
149 | 149 | ||
150 | If unsure, say Y. | 150 | If unsure, say Y. |
151 | 151 | ||
152 | config MOUSE_PS2_VMMOUSE | ||
153 | bool "Virtual mouse (vmmouse)" | ||
154 | depends on MOUSE_PS2 && X86 && HYPERVISOR_GUEST | ||
155 | help | ||
156 | Say Y here if you are running under control of VMware hypervisor | ||
157 | (ESXi, Workstation or Fusion). Also make sure that when you enable | ||
158 | this option, you remove the xf86-input-vmmouse user-space driver | ||
159 | or upgrade it to at least xf86-input-vmmouse 13.0.1, which doesn't | ||
160 | load in the presence of an in-kernel vmmouse driver. | ||
161 | |||
162 | If unsure, say N. | ||
163 | |||
152 | config MOUSE_SERIAL | 164 | config MOUSE_SERIAL |
153 | tristate "Serial mouse" | 165 | tristate "Serial mouse" |
154 | select SERIO | 166 | select SERIO |
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 8a9c98e76d9c..793300bfbddd 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile | |||
@@ -36,6 +36,7 @@ psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o | |||
36 | psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o | 36 | psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o |
37 | psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o | 37 | psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o |
38 | psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o | 38 | psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o |
39 | psmouse-$(CONFIG_MOUSE_PS2_VMMOUSE) += vmmouse.o | ||
39 | 40 | ||
40 | elan_i2c-objs := elan_i2c_core.o | 41 | elan_i2c-objs := elan_i2c_core.o |
41 | elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_I2C) += elan_i2c_i2c.o | 42 | elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_I2C) += elan_i2c_i2c.o |
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 58f4f6fa4857..efe148474e7f 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c | |||
@@ -723,7 +723,7 @@ static ssize_t cyapa_update_suspend_scanrate(struct device *dev, | |||
723 | } else if (sysfs_streq(buf, OFF_MODE_NAME)) { | 723 | } else if (sysfs_streq(buf, OFF_MODE_NAME)) { |
724 | cyapa->suspend_power_mode = PWR_MODE_OFF; | 724 | cyapa->suspend_power_mode = PWR_MODE_OFF; |
725 | } else if (!kstrtou16(buf, 10, &sleep_time)) { | 725 | } else if (!kstrtou16(buf, 10, &sleep_time)) { |
726 | cyapa->suspend_sleep_time = max_t(u16, sleep_time, 1000); | 726 | cyapa->suspend_sleep_time = min_t(u16, sleep_time, 1000); |
727 | cyapa->suspend_power_mode = | 727 | cyapa->suspend_power_mode = |
728 | cyapa_sleep_time_to_pwr_cmd(cyapa->suspend_sleep_time); | 728 | cyapa_sleep_time_to_pwr_cmd(cyapa->suspend_sleep_time); |
729 | } else { | 729 | } else { |
@@ -840,7 +840,7 @@ static ssize_t cyapa_update_rt_suspend_scanrate(struct device *dev, | |||
840 | if (error) | 840 | if (error) |
841 | return error; | 841 | return error; |
842 | 842 | ||
843 | cyapa->runtime_suspend_sleep_time = max_t(u16, time, 1000); | 843 | cyapa->runtime_suspend_sleep_time = min_t(u16, time, 1000); |
844 | cyapa->runtime_suspend_power_mode = | 844 | cyapa->runtime_suspend_power_mode = |
845 | cyapa_sleep_time_to_pwr_cmd(cyapa->runtime_suspend_sleep_time); | 845 | cyapa_sleep_time_to_pwr_cmd(cyapa->runtime_suspend_sleep_time); |
846 | 846 | ||
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index 9b2dc015f20c..6d5f8a4c1748 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #define ETP_ENABLE_CALIBRATE 0x0002 | 25 | #define ETP_ENABLE_CALIBRATE 0x0002 |
26 | #define ETP_DISABLE_CALIBRATE 0x0000 | 26 | #define ETP_DISABLE_CALIBRATE 0x0000 |
27 | #define ETP_DISABLE_POWER 0x0001 | 27 | #define ETP_DISABLE_POWER 0x0001 |
28 | #define ETP_PRESSURE_OFFSET 25 | ||
28 | 29 | ||
29 | /* IAP Firmware handling */ | 30 | /* IAP Firmware handling */ |
30 | #define ETP_FW_NAME "elan_i2c.bin" | 31 | #define ETP_FW_NAME "elan_i2c.bin" |
@@ -79,6 +80,8 @@ struct elan_transport_ops { | |||
79 | struct completion *reset_done); | 80 | struct completion *reset_done); |
80 | 81 | ||
81 | int (*get_report)(struct i2c_client *client, u8 *report); | 82 | int (*get_report)(struct i2c_client *client, u8 *report); |
83 | int (*get_pressure_adjustment)(struct i2c_client *client, | ||
84 | int *adjustment); | ||
82 | }; | 85 | }; |
83 | 86 | ||
84 | extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops; | 87 | extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops; |
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 375d98f47483..fd5068b2542d 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright (c) 2013 ELAN Microelectronics Corp. | 4 | * Copyright (c) 2013 ELAN Microelectronics Corp. |
5 | * | 5 | * |
6 | * Author: ćž—ć”żç¶ (Duson Lin) <dusonlin@emc.com.tw> | 6 | * Author: ćž—ć”żç¶ (Duson Lin) <dusonlin@emc.com.tw> |
7 | * Version: 1.5.6 | 7 | * Version: 1.5.7 |
8 | * | 8 | * |
9 | * Based on cyapa driver: | 9 | * Based on cyapa driver: |
10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. | 10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
@@ -40,8 +40,7 @@ | |||
40 | #include "elan_i2c.h" | 40 | #include "elan_i2c.h" |
41 | 41 | ||
42 | #define DRIVER_NAME "elan_i2c" | 42 | #define DRIVER_NAME "elan_i2c" |
43 | #define ELAN_DRIVER_VERSION "1.5.6" | 43 | #define ELAN_DRIVER_VERSION "1.5.7" |
44 | #define ETP_PRESSURE_OFFSET 25 | ||
45 | #define ETP_MAX_PRESSURE 255 | 44 | #define ETP_MAX_PRESSURE 255 |
46 | #define ETP_FWIDTH_REDUCE 90 | 45 | #define ETP_FWIDTH_REDUCE 90 |
47 | #define ETP_FINGER_WIDTH 15 | 46 | #define ETP_FINGER_WIDTH 15 |
@@ -53,6 +52,7 @@ | |||
53 | #define ETP_REPORT_ID_OFFSET 2 | 52 | #define ETP_REPORT_ID_OFFSET 2 |
54 | #define ETP_TOUCH_INFO_OFFSET 3 | 53 | #define ETP_TOUCH_INFO_OFFSET 3 |
55 | #define ETP_FINGER_DATA_OFFSET 4 | 54 | #define ETP_FINGER_DATA_OFFSET 4 |
55 | #define ETP_HOVER_INFO_OFFSET 30 | ||
56 | #define ETP_MAX_REPORT_LEN 34 | 56 | #define ETP_MAX_REPORT_LEN 34 |
57 | 57 | ||
58 | /* The main device structure */ | 58 | /* The main device structure */ |
@@ -81,7 +81,7 @@ struct elan_tp_data { | |||
81 | u8 sm_version; | 81 | u8 sm_version; |
82 | u8 iap_version; | 82 | u8 iap_version; |
83 | u16 fw_checksum; | 83 | u16 fw_checksum; |
84 | 84 | int pressure_adjustment; | |
85 | u8 mode; | 85 | u8 mode; |
86 | 86 | ||
87 | bool irq_wake; | 87 | bool irq_wake; |
@@ -229,6 +229,11 @@ static int elan_query_device_info(struct elan_tp_data *data) | |||
229 | if (error) | 229 | if (error) |
230 | return error; | 230 | return error; |
231 | 231 | ||
232 | error = data->ops->get_pressure_adjustment(data->client, | ||
233 | &data->pressure_adjustment); | ||
234 | if (error) | ||
235 | return error; | ||
236 | |||
232 | return 0; | 237 | return 0; |
233 | } | 238 | } |
234 | 239 | ||
@@ -721,13 +726,13 @@ static const struct attribute_group *elan_sysfs_groups[] = { | |||
721 | */ | 726 | */ |
722 | static void elan_report_contact(struct elan_tp_data *data, | 727 | static void elan_report_contact(struct elan_tp_data *data, |
723 | int contact_num, bool contact_valid, | 728 | int contact_num, bool contact_valid, |
724 | u8 *finger_data) | 729 | bool hover_event, u8 *finger_data) |
725 | { | 730 | { |
726 | struct input_dev *input = data->input; | 731 | struct input_dev *input = data->input; |
727 | unsigned int pos_x, pos_y; | 732 | unsigned int pos_x, pos_y; |
728 | unsigned int pressure, mk_x, mk_y; | 733 | unsigned int pressure, mk_x, mk_y; |
729 | unsigned int area_x, area_y, major, minor, new_pressure; | 734 | unsigned int area_x, area_y, major, minor; |
730 | 735 | unsigned int scaled_pressure; | |
731 | 736 | ||
732 | if (contact_valid) { | 737 | if (contact_valid) { |
733 | pos_x = ((finger_data[0] & 0xf0) << 4) | | 738 | pos_x = ((finger_data[0] & 0xf0) << 4) | |
@@ -756,15 +761,18 @@ static void elan_report_contact(struct elan_tp_data *data, | |||
756 | major = max(area_x, area_y); | 761 | major = max(area_x, area_y); |
757 | minor = min(area_x, area_y); | 762 | minor = min(area_x, area_y); |
758 | 763 | ||
759 | new_pressure = pressure + ETP_PRESSURE_OFFSET; | 764 | scaled_pressure = pressure + data->pressure_adjustment; |
760 | if (new_pressure > ETP_MAX_PRESSURE) | 765 | |
761 | new_pressure = ETP_MAX_PRESSURE; | 766 | if (scaled_pressure > ETP_MAX_PRESSURE) |
767 | scaled_pressure = ETP_MAX_PRESSURE; | ||
762 | 768 | ||
763 | input_mt_slot(input, contact_num); | 769 | input_mt_slot(input, contact_num); |
764 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | 770 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); |
765 | input_report_abs(input, ABS_MT_POSITION_X, pos_x); | 771 | input_report_abs(input, ABS_MT_POSITION_X, pos_x); |
766 | input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y); | 772 | input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y); |
767 | input_report_abs(input, ABS_MT_PRESSURE, new_pressure); | 773 | input_report_abs(input, ABS_MT_DISTANCE, hover_event); |
774 | input_report_abs(input, ABS_MT_PRESSURE, | ||
775 | hover_event ? 0 : scaled_pressure); | ||
768 | input_report_abs(input, ABS_TOOL_WIDTH, mk_x); | 776 | input_report_abs(input, ABS_TOOL_WIDTH, mk_x); |
769 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); | 777 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); |
770 | input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); | 778 | input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); |
@@ -780,11 +788,14 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) | |||
780 | u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET]; | 788 | u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET]; |
781 | int i; | 789 | int i; |
782 | u8 tp_info = packet[ETP_TOUCH_INFO_OFFSET]; | 790 | u8 tp_info = packet[ETP_TOUCH_INFO_OFFSET]; |
783 | bool contact_valid; | 791 | u8 hover_info = packet[ETP_HOVER_INFO_OFFSET]; |
792 | bool contact_valid, hover_event; | ||
784 | 793 | ||
794 | hover_event = hover_info & 0x40; | ||
785 | for (i = 0; i < ETP_MAX_FINGERS; i++) { | 795 | for (i = 0; i < ETP_MAX_FINGERS; i++) { |
786 | contact_valid = tp_info & (1U << (3 + i)); | 796 | contact_valid = tp_info & (1U << (3 + i)); |
787 | elan_report_contact(data, i, contact_valid, finger_data); | 797 | elan_report_contact(data, i, contact_valid, hover_event, |
798 | finger_data); | ||
788 | 799 | ||
789 | if (contact_valid) | 800 | if (contact_valid) |
790 | finger_data += ETP_FINGER_DATA_LEN; | 801 | finger_data += ETP_FINGER_DATA_LEN; |
@@ -878,6 +889,7 @@ static int elan_setup_input_device(struct elan_tp_data *data) | |||
878 | ETP_FINGER_WIDTH * max_width, 0, 0); | 889 | ETP_FINGER_WIDTH * max_width, 0, 0); |
879 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, | 890 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, |
880 | ETP_FINGER_WIDTH * min_width, 0, 0); | 891 | ETP_FINGER_WIDTH * min_width, 0, 0); |
892 | input_set_abs_params(input, ABS_MT_DISTANCE, 0, 1, 0, 0); | ||
881 | 893 | ||
882 | data->input = input; | 894 | data->input = input; |
883 | 895 | ||
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 6cf0def6d35e..a0acbbf83bfd 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #define ETP_I2C_MAX_X_AXIS_CMD 0x0106 | 41 | #define ETP_I2C_MAX_X_AXIS_CMD 0x0106 |
42 | #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 | 42 | #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 |
43 | #define ETP_I2C_RESOLUTION_CMD 0x0108 | 43 | #define ETP_I2C_RESOLUTION_CMD 0x0108 |
44 | #define ETP_I2C_PRESSURE_CMD 0x010A | ||
44 | #define ETP_I2C_IAP_VERSION_CMD 0x0110 | 45 | #define ETP_I2C_IAP_VERSION_CMD 0x0110 |
45 | #define ETP_I2C_SET_CMD 0x0300 | 46 | #define ETP_I2C_SET_CMD 0x0300 |
46 | #define ETP_I2C_POWER_CMD 0x0307 | 47 | #define ETP_I2C_POWER_CMD 0x0307 |
@@ -364,8 +365,29 @@ static int elan_i2c_get_num_traces(struct i2c_client *client, | |||
364 | return error; | 365 | return error; |
365 | } | 366 | } |
366 | 367 | ||
367 | *x_traces = val[0] - 1; | 368 | *x_traces = val[0]; |
368 | *y_traces = val[1] - 1; | 369 | *y_traces = val[1]; |
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int elan_i2c_get_pressure_adjustment(struct i2c_client *client, | ||
375 | int *adjustment) | ||
376 | { | ||
377 | int error; | ||
378 | u8 val[3]; | ||
379 | |||
380 | error = elan_i2c_read_cmd(client, ETP_I2C_PRESSURE_CMD, val); | ||
381 | if (error) { | ||
382 | dev_err(&client->dev, "failed to get pressure format: %d\n", | ||
383 | error); | ||
384 | return error; | ||
385 | } | ||
386 | |||
387 | if ((val[0] >> 4) & 0x1) | ||
388 | *adjustment = 0; | ||
389 | else | ||
390 | *adjustment = ETP_PRESSURE_OFFSET; | ||
369 | 391 | ||
370 | return 0; | 392 | return 0; |
371 | } | 393 | } |
@@ -602,6 +624,7 @@ const struct elan_transport_ops elan_i2c_ops = { | |||
602 | .get_sm_version = elan_i2c_get_sm_version, | 624 | .get_sm_version = elan_i2c_get_sm_version, |
603 | .get_product_id = elan_i2c_get_product_id, | 625 | .get_product_id = elan_i2c_get_product_id, |
604 | .get_checksum = elan_i2c_get_checksum, | 626 | .get_checksum = elan_i2c_get_checksum, |
627 | .get_pressure_adjustment = elan_i2c_get_pressure_adjustment, | ||
605 | 628 | ||
606 | .get_max = elan_i2c_get_max, | 629 | .get_max = elan_i2c_get_max, |
607 | .get_resolution = elan_i2c_get_resolution, | 630 | .get_resolution = elan_i2c_get_resolution, |
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 06a2bcd1cda2..30ab80dbcdd6 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c | |||
@@ -268,12 +268,19 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, | |||
268 | return error; | 268 | return error; |
269 | } | 269 | } |
270 | 270 | ||
271 | *x_traces = val[1] - 1; | 271 | *x_traces = val[1]; |
272 | *y_traces = val[2] - 1; | 272 | *y_traces = val[2]; |
273 | 273 | ||
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | static int elan_smbus_get_pressure_adjustment(struct i2c_client *client, | ||
278 | int *adjustment) | ||
279 | { | ||
280 | *adjustment = ETP_PRESSURE_OFFSET; | ||
281 | return 0; | ||
282 | } | ||
283 | |||
277 | static int elan_smbus_iap_get_mode(struct i2c_client *client, | 284 | static int elan_smbus_iap_get_mode(struct i2c_client *client, |
278 | enum tp_mode *mode) | 285 | enum tp_mode *mode) |
279 | { | 286 | { |
@@ -497,6 +504,7 @@ const struct elan_transport_ops elan_smbus_ops = { | |||
497 | .get_sm_version = elan_smbus_get_sm_version, | 504 | .get_sm_version = elan_smbus_get_sm_version, |
498 | .get_product_id = elan_smbus_get_product_id, | 505 | .get_product_id = elan_smbus_get_product_id, |
499 | .get_checksum = elan_smbus_get_checksum, | 506 | .get_checksum = elan_smbus_get_checksum, |
507 | .get_pressure_adjustment = elan_smbus_get_pressure_adjustment, | ||
500 | 508 | ||
501 | .get_max = elan_smbus_get_max, | 509 | .get_max = elan_smbus_get_max, |
502 | .get_resolution = elan_smbus_get_resolution, | 510 | .get_resolution = elan_smbus_get_resolution, |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 27057df7ba74..5bb1658f60c7 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "sentelic.h" | 36 | #include "sentelic.h" |
37 | #include "cypress_ps2.h" | 37 | #include "cypress_ps2.h" |
38 | #include "focaltech.h" | 38 | #include "focaltech.h" |
39 | #include "vmmouse.h" | ||
39 | 40 | ||
40 | #define DRIVER_DESC "PS/2 mouse driver" | 41 | #define DRIVER_DESC "PS/2 mouse driver" |
41 | 42 | ||
@@ -790,6 +791,13 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
790 | } | 791 | } |
791 | } | 792 | } |
792 | 793 | ||
794 | if (psmouse_do_detect(vmmouse_detect, psmouse, set_properties) == 0) { | ||
795 | if (max_proto > PSMOUSE_IMEX) { | ||
796 | if (!set_properties || vmmouse_init(psmouse) == 0) | ||
797 | return PSMOUSE_VMMOUSE; | ||
798 | } | ||
799 | } | ||
800 | |||
793 | /* | 801 | /* |
794 | * Try Kensington ThinkingMouse (we try first, because synaptics probe | 802 | * Try Kensington ThinkingMouse (we try first, because synaptics probe |
795 | * upsets the thinkingmouse). | 803 | * upsets the thinkingmouse). |
@@ -1113,6 +1121,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { | |||
1113 | .init = focaltech_init, | 1121 | .init = focaltech_init, |
1114 | }, | 1122 | }, |
1115 | #endif | 1123 | #endif |
1124 | #ifdef CONFIG_MOUSE_PS2_VMMOUSE | ||
1125 | { | ||
1126 | .type = PSMOUSE_VMMOUSE, | ||
1127 | .name = VMMOUSE_PSNAME, | ||
1128 | .alias = "vmmouse", | ||
1129 | .detect = vmmouse_detect, | ||
1130 | .init = vmmouse_init, | ||
1131 | }, | ||
1132 | #endif | ||
1116 | { | 1133 | { |
1117 | .type = PSMOUSE_AUTO, | 1134 | .type = PSMOUSE_AUTO, |
1118 | .name = "auto", | 1135 | .name = "auto", |
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index d02e1bdc9ae4..ad5a5a1ea872 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
@@ -103,6 +103,7 @@ enum psmouse_type { | |||
103 | PSMOUSE_SYNAPTICS_RELATIVE, | 103 | PSMOUSE_SYNAPTICS_RELATIVE, |
104 | PSMOUSE_CYPRESS, | 104 | PSMOUSE_CYPRESS, |
105 | PSMOUSE_FOCALTECH, | 105 | PSMOUSE_FOCALTECH, |
106 | PSMOUSE_VMMOUSE, | ||
106 | PSMOUSE_AUTO /* This one should always be last */ | 107 | PSMOUSE_AUTO /* This one should always be last */ |
107 | }; | 108 | }; |
108 | 109 | ||
diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c new file mode 100644 index 000000000000..e272f06258ce --- /dev/null +++ b/drivers/input/mouse/vmmouse.c | |||
@@ -0,0 +1,508 @@ | |||
1 | /* | ||
2 | * Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors. | ||
3 | * | ||
4 | * Copyright (C) 2014, VMware, Inc. All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | * | ||
10 | * Twin device code is hugely inspired by the ALPS driver. | ||
11 | * Authors: | ||
12 | * Dmitry Torokhov <dmitry.torokhov@gmail.com> | ||
13 | * Thomas Hellstrom <thellstrom@vmware.com> | ||
14 | */ | ||
15 | |||
16 | #include <linux/input.h> | ||
17 | #include <linux/serio.h> | ||
18 | #include <linux/libps2.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <asm/hypervisor.h> | ||
22 | |||
23 | #include "psmouse.h" | ||
24 | #include "vmmouse.h" | ||
25 | |||
26 | #define VMMOUSE_PROTO_MAGIC 0x564D5868U | ||
27 | #define VMMOUSE_PROTO_PORT 0x5658 | ||
28 | |||
29 | /* | ||
30 | * Main commands supported by the vmmouse hypervisor port. | ||
31 | */ | ||
32 | #define VMMOUSE_PROTO_CMD_GETVERSION 10 | ||
33 | #define VMMOUSE_PROTO_CMD_ABSPOINTER_DATA 39 | ||
34 | #define VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS 40 | ||
35 | #define VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND 41 | ||
36 | #define VMMOUSE_PROTO_CMD_ABSPOINTER_RESTRICT 86 | ||
37 | |||
38 | /* | ||
39 | * Subcommands for VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND | ||
40 | */ | ||
41 | #define VMMOUSE_CMD_ENABLE 0x45414552U | ||
42 | #define VMMOUSE_CMD_DISABLE 0x000000f5U | ||
43 | #define VMMOUSE_CMD_REQUEST_RELATIVE 0x4c455252U | ||
44 | #define VMMOUSE_CMD_REQUEST_ABSOLUTE 0x53424152U | ||
45 | |||
46 | #define VMMOUSE_ERROR 0xffff0000U | ||
47 | |||
48 | #define VMMOUSE_VERSION_ID 0x3442554aU | ||
49 | |||
50 | #define VMMOUSE_RELATIVE_PACKET 0x00010000U | ||
51 | |||
52 | #define VMMOUSE_LEFT_BUTTON 0x20 | ||
53 | #define VMMOUSE_RIGHT_BUTTON 0x10 | ||
54 | #define VMMOUSE_MIDDLE_BUTTON 0x08 | ||
55 | |||
56 | /* | ||
57 | * VMMouse Restrict command | ||
58 | */ | ||
59 | #define VMMOUSE_RESTRICT_ANY 0x00 | ||
60 | #define VMMOUSE_RESTRICT_CPL0 0x01 | ||
61 | #define VMMOUSE_RESTRICT_IOPL 0x02 | ||
62 | |||
63 | #define VMMOUSE_MAX_X 0xFFFF | ||
64 | #define VMMOUSE_MAX_Y 0xFFFF | ||
65 | |||
66 | #define VMMOUSE_VENDOR "VMware" | ||
67 | #define VMMOUSE_NAME "VMMouse" | ||
68 | |||
69 | /** | ||
70 | * struct vmmouse_data - private data structure for the vmmouse driver | ||
71 | * | ||
72 | * @abs_dev: "Absolute" device used to report absolute mouse movement. | ||
73 | * @phys: Physical path for the absolute device. | ||
74 | * @dev_name: Name attribute name for the absolute device. | ||
75 | */ | ||
76 | struct vmmouse_data { | ||
77 | struct input_dev *abs_dev; | ||
78 | char phys[32]; | ||
79 | char dev_name[128]; | ||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * Hypervisor-specific bi-directional communication channel | ||
84 | * implementing the vmmouse protocol. Should never execute on | ||
85 | * bare metal hardware. | ||
86 | */ | ||
87 | #define VMMOUSE_CMD(cmd, in1, out1, out2, out3, out4) \ | ||
88 | ({ \ | ||
89 | unsigned long __dummy1, __dummy2; \ | ||
90 | __asm__ __volatile__ ("inl %%dx" : \ | ||
91 | "=a"(out1), \ | ||
92 | "=b"(out2), \ | ||
93 | "=c"(out3), \ | ||
94 | "=d"(out4), \ | ||
95 | "=S"(__dummy1), \ | ||
96 | "=D"(__dummy2) : \ | ||
97 | "a"(VMMOUSE_PROTO_MAGIC), \ | ||
98 | "b"(in1), \ | ||
99 | "c"(VMMOUSE_PROTO_CMD_##cmd), \ | ||
100 | "d"(VMMOUSE_PROTO_PORT) : \ | ||
101 | "memory"); \ | ||
102 | }) | ||
103 | |||
104 | /** | ||
105 | * vmmouse_report_button - report button state on the correct input device | ||
106 | * | ||
107 | * @psmouse: Pointer to the psmouse struct | ||
108 | * @abs_dev: The absolute input device | ||
109 | * @rel_dev: The relative input device | ||
110 | * @pref_dev: The preferred device for reporting | ||
111 | * @code: Button code | ||
112 | * @value: Button value | ||
113 | * | ||
114 | * Report @value and @code on @pref_dev, unless the button is already | ||
115 | * pressed on the other device, in which case the state is reported on that | ||
116 | * device. | ||
117 | */ | ||
118 | static void vmmouse_report_button(struct psmouse *psmouse, | ||
119 | struct input_dev *abs_dev, | ||
120 | struct input_dev *rel_dev, | ||
121 | struct input_dev *pref_dev, | ||
122 | unsigned int code, int value) | ||
123 | { | ||
124 | if (test_bit(code, abs_dev->key)) | ||
125 | pref_dev = abs_dev; | ||
126 | else if (test_bit(code, rel_dev->key)) | ||
127 | pref_dev = rel_dev; | ||
128 | |||
129 | input_report_key(pref_dev, code, value); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * vmmouse_report_events - process events on the vmmouse communications channel | ||
134 | * | ||
135 | * @psmouse: Pointer to the psmouse struct | ||
136 | * | ||
137 | * This function pulls events from the vmmouse communications channel and | ||
138 | * reports them on the correct (absolute or relative) input device. When the | ||
139 | * communications channel is drained, or if we've processed more than 255 | ||
140 | * psmouse commands, the function returns PSMOUSE_FULL_PACKET. If there is a | ||
141 | * host- or synchronization error, the function returns PSMOUSE_BAD_DATA in | ||
142 | * the hope that the caller will reset the communications channel. | ||
143 | */ | ||
144 | static psmouse_ret_t vmmouse_report_events(struct psmouse *psmouse) | ||
145 | { | ||
146 | struct input_dev *rel_dev = psmouse->dev; | ||
147 | struct vmmouse_data *priv = psmouse->private; | ||
148 | struct input_dev *abs_dev = priv->abs_dev; | ||
149 | struct input_dev *pref_dev; | ||
150 | u32 status, x, y, z; | ||
151 | u32 dummy1, dummy2, dummy3; | ||
152 | unsigned int queue_length; | ||
153 | unsigned int count = 255; | ||
154 | |||
155 | while (count--) { | ||
156 | /* See if we have motion data. */ | ||
157 | VMMOUSE_CMD(ABSPOINTER_STATUS, 0, | ||
158 | status, dummy1, dummy2, dummy3); | ||
159 | if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) { | ||
160 | psmouse_err(psmouse, "failed to fetch status data\n"); | ||
161 | /* | ||
162 | * After a few attempts this will result in | ||
163 | * reconnect. | ||
164 | */ | ||
165 | return PSMOUSE_BAD_DATA; | ||
166 | } | ||
167 | |||
168 | queue_length = status & 0xffff; | ||
169 | if (queue_length == 0) | ||
170 | break; | ||
171 | |||
172 | if (queue_length % 4) { | ||
173 | psmouse_err(psmouse, "invalid queue length\n"); | ||
174 | return PSMOUSE_BAD_DATA; | ||
175 | } | ||
176 | |||
177 | /* Now get it */ | ||
178 | VMMOUSE_CMD(ABSPOINTER_DATA, 4, status, x, y, z); | ||
179 | |||
180 | /* | ||
181 | * And report what we've got. Prefer to report button | ||
182 | * events on the same device where we report motion events. | ||
183 | * This doesn't work well with the mouse wheel, though. See | ||
184 | * below. Ideally we would want to report that on the | ||
185 | * preferred device as well. | ||
186 | */ | ||
187 | if (status & VMMOUSE_RELATIVE_PACKET) { | ||
188 | pref_dev = rel_dev; | ||
189 | input_report_rel(rel_dev, REL_X, (s32)x); | ||
190 | input_report_rel(rel_dev, REL_Y, -(s32)y); | ||
191 | } else { | ||
192 | pref_dev = abs_dev; | ||
193 | input_report_abs(abs_dev, ABS_X, x); | ||
194 | input_report_abs(abs_dev, ABS_Y, y); | ||
195 | } | ||
196 | |||
197 | /* Xorg seems to ignore wheel events on absolute devices */ | ||
198 | input_report_rel(rel_dev, REL_WHEEL, -(s8)((u8) z)); | ||
199 | |||
200 | vmmouse_report_button(psmouse, abs_dev, rel_dev, | ||
201 | pref_dev, BTN_LEFT, | ||
202 | status & VMMOUSE_LEFT_BUTTON); | ||
203 | vmmouse_report_button(psmouse, abs_dev, rel_dev, | ||
204 | pref_dev, BTN_RIGHT, | ||
205 | status & VMMOUSE_RIGHT_BUTTON); | ||
206 | vmmouse_report_button(psmouse, abs_dev, rel_dev, | ||
207 | pref_dev, BTN_MIDDLE, | ||
208 | status & VMMOUSE_MIDDLE_BUTTON); | ||
209 | input_sync(abs_dev); | ||
210 | input_sync(rel_dev); | ||
211 | } | ||
212 | |||
213 | return PSMOUSE_FULL_PACKET; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * vmmouse_process_byte - process data on the ps/2 channel | ||
218 | * | ||
219 | * @psmouse: Pointer to the psmouse struct | ||
220 | * | ||
221 | * When the ps/2 channel indicates that there is vmmouse data available, | ||
222 | * call vmmouse channel processing. Otherwise, continue to accept bytes. If | ||
223 | * there is a synchronization or communication data error, return | ||
224 | * PSMOUSE_BAD_DATA in the hope that the caller will reset the mouse. | ||
225 | */ | ||
226 | static psmouse_ret_t vmmouse_process_byte(struct psmouse *psmouse) | ||
227 | { | ||
228 | unsigned char *packet = psmouse->packet; | ||
229 | |||
230 | switch (psmouse->pktcnt) { | ||
231 | case 1: | ||
232 | return (packet[0] & 0x8) == 0x8 ? | ||
233 | PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; | ||
234 | |||
235 | case 2: | ||
236 | return PSMOUSE_GOOD_DATA; | ||
237 | |||
238 | default: | ||
239 | return vmmouse_report_events(psmouse); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | /** | ||
244 | * vmmouse_disable - Disable vmmouse | ||
245 | * | ||
246 | * @psmouse: Pointer to the psmouse struct | ||
247 | * | ||
248 | * Tries to disable vmmouse mode. | ||
249 | */ | ||
250 | static void vmmouse_disable(struct psmouse *psmouse) | ||
251 | { | ||
252 | u32 status; | ||
253 | u32 dummy1, dummy2, dummy3, dummy4; | ||
254 | |||
255 | VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_DISABLE, | ||
256 | dummy1, dummy2, dummy3, dummy4); | ||
257 | |||
258 | VMMOUSE_CMD(ABSPOINTER_STATUS, 0, | ||
259 | status, dummy1, dummy2, dummy3); | ||
260 | |||
261 | if ((status & VMMOUSE_ERROR) != VMMOUSE_ERROR) | ||
262 | psmouse_warn(psmouse, "failed to disable vmmouse device\n"); | ||
263 | } | ||
264 | |||
265 | /** | ||
266 | * vmmouse_enable - Enable vmmouse and request absolute mode. | ||
267 | * | ||
268 | * @psmouse: Pointer to the psmouse struct | ||
269 | * | ||
270 | * Tries to enable vmmouse mode. Performs basic checks and requests | ||
271 | * absolute vmmouse mode. | ||
272 | * Returns 0 on success, -ENODEV on failure. | ||
273 | */ | ||
274 | static int vmmouse_enable(struct psmouse *psmouse) | ||
275 | { | ||
276 | u32 status, version; | ||
277 | u32 dummy1, dummy2, dummy3, dummy4; | ||
278 | |||
279 | /* | ||
280 | * Try enabling the device. If successful, we should be able to | ||
281 | * read valid version ID back from it. | ||
282 | */ | ||
283 | VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_ENABLE, | ||
284 | dummy1, dummy2, dummy3, dummy4); | ||
285 | |||
286 | /* | ||
287 | * See if version ID can be retrieved. | ||
288 | */ | ||
289 | VMMOUSE_CMD(ABSPOINTER_STATUS, 0, status, dummy1, dummy2, dummy3); | ||
290 | if ((status & 0x0000ffff) == 0) { | ||
291 | psmouse_dbg(psmouse, "empty flags - assuming no device\n"); | ||
292 | return -ENXIO; | ||
293 | } | ||
294 | |||
295 | VMMOUSE_CMD(ABSPOINTER_DATA, 1 /* single item */, | ||
296 | version, dummy1, dummy2, dummy3); | ||
297 | if (version != VMMOUSE_VERSION_ID) { | ||
298 | psmouse_dbg(psmouse, "Unexpected version value: %u vs %u\n", | ||
299 | (unsigned) version, VMMOUSE_VERSION_ID); | ||
300 | vmmouse_disable(psmouse); | ||
301 | return -ENXIO; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Restrict ioport access, if possible. | ||
306 | */ | ||
307 | VMMOUSE_CMD(ABSPOINTER_RESTRICT, VMMOUSE_RESTRICT_CPL0, | ||
308 | dummy1, dummy2, dummy3, dummy4); | ||
309 | |||
310 | VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_REQUEST_ABSOLUTE, | ||
311 | dummy1, dummy2, dummy3, dummy4); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * Array of supported hypervisors. | ||
318 | */ | ||
319 | static const struct hypervisor_x86 *vmmouse_supported_hypervisors[] = { | ||
320 | &x86_hyper_vmware, | ||
321 | #ifdef CONFIG_KVM_GUEST | ||
322 | &x86_hyper_kvm, | ||
323 | #endif | ||
324 | }; | ||
325 | |||
326 | /** | ||
327 | * vmmouse_check_hypervisor - Check if we're running on a supported hypervisor | ||
328 | */ | ||
329 | static bool vmmouse_check_hypervisor(void) | ||
330 | { | ||
331 | int i; | ||
332 | |||
333 | for (i = 0; i < ARRAY_SIZE(vmmouse_supported_hypervisors); i++) | ||
334 | if (vmmouse_supported_hypervisors[i] == x86_hyper) | ||
335 | return true; | ||
336 | |||
337 | return false; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * vmmouse_detect - Probe whether vmmouse is available | ||
342 | * | ||
343 | * @psmouse: Pointer to the psmouse struct | ||
344 | * @set_properties: Whether to set psmouse name and vendor | ||
345 | * | ||
346 | * Returns 0 if vmmouse channel is available. Negative error code if not. | ||
347 | */ | ||
348 | int vmmouse_detect(struct psmouse *psmouse, bool set_properties) | ||
349 | { | ||
350 | u32 response, version, dummy1, dummy2; | ||
351 | |||
352 | if (!vmmouse_check_hypervisor()) { | ||
353 | psmouse_dbg(psmouse, | ||
354 | "VMMouse not running on supported hypervisor.\n"); | ||
355 | return -ENXIO; | ||
356 | } | ||
357 | |||
358 | if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) { | ||
359 | psmouse_dbg(psmouse, "VMMouse port in use.\n"); | ||
360 | return -EBUSY; | ||
361 | } | ||
362 | |||
363 | /* Check if the device is present */ | ||
364 | response = ~VMMOUSE_PROTO_MAGIC; | ||
365 | VMMOUSE_CMD(GETVERSION, 0, version, response, dummy1, dummy2); | ||
366 | if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU) { | ||
367 | release_region(VMMOUSE_PROTO_PORT, 4); | ||
368 | return -ENXIO; | ||
369 | } | ||
370 | |||
371 | if (set_properties) { | ||
372 | psmouse->vendor = VMMOUSE_VENDOR; | ||
373 | psmouse->name = VMMOUSE_NAME; | ||
374 | psmouse->model = version; | ||
375 | } | ||
376 | |||
377 | release_region(VMMOUSE_PROTO_PORT, 4); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /** | ||
383 | * vmmouse_disconnect - Take down vmmouse driver | ||
384 | * | ||
385 | * @psmouse: Pointer to the psmouse struct | ||
386 | * | ||
387 | * Takes down vmmouse driver and frees resources set up in vmmouse_init(). | ||
388 | */ | ||
389 | static void vmmouse_disconnect(struct psmouse *psmouse) | ||
390 | { | ||
391 | struct vmmouse_data *priv = psmouse->private; | ||
392 | |||
393 | vmmouse_disable(psmouse); | ||
394 | psmouse_reset(psmouse); | ||
395 | input_unregister_device(priv->abs_dev); | ||
396 | kfree(priv); | ||
397 | release_region(VMMOUSE_PROTO_PORT, 4); | ||
398 | } | ||
399 | |||
400 | /** | ||
401 | * vmmouse_reconnect - Reset the ps/2 - and vmmouse connections | ||
402 | * | ||
403 | * @psmouse: Pointer to the psmouse struct | ||
404 | * | ||
405 | * Attempts to reset the mouse connections. Returns 0 on success and | ||
406 | * -1 on failure. | ||
407 | */ | ||
408 | static int vmmouse_reconnect(struct psmouse *psmouse) | ||
409 | { | ||
410 | int error; | ||
411 | |||
412 | psmouse_reset(psmouse); | ||
413 | vmmouse_disable(psmouse); | ||
414 | error = vmmouse_enable(psmouse); | ||
415 | if (error) { | ||
416 | psmouse_err(psmouse, | ||
417 | "Unable to re-enable mouse when reconnecting, err: %d\n", | ||
418 | error); | ||
419 | return error; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | /** | ||
426 | * vmmouse_init - Initialize the vmmouse driver | ||
427 | * | ||
428 | * @psmouse: Pointer to the psmouse struct | ||
429 | * | ||
430 | * Requests the device and tries to enable vmmouse mode. | ||
431 | * If successful, sets up the input device for relative movement events. | ||
432 | * It also allocates another input device and sets it up for absolute motion | ||
433 | * events. Returns 0 on success and -1 on failure. | ||
434 | */ | ||
435 | int vmmouse_init(struct psmouse *psmouse) | ||
436 | { | ||
437 | struct vmmouse_data *priv; | ||
438 | struct input_dev *rel_dev = psmouse->dev, *abs_dev; | ||
439 | int error; | ||
440 | |||
441 | if (!request_region(VMMOUSE_PROTO_PORT, 4, "vmmouse")) { | ||
442 | psmouse_dbg(psmouse, "VMMouse port in use.\n"); | ||
443 | return -EBUSY; | ||
444 | } | ||
445 | |||
446 | psmouse_reset(psmouse); | ||
447 | error = vmmouse_enable(psmouse); | ||
448 | if (error) | ||
449 | goto release_region; | ||
450 | |||
451 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
452 | abs_dev = input_allocate_device(); | ||
453 | if (!priv || !abs_dev) { | ||
454 | error = -ENOMEM; | ||
455 | goto init_fail; | ||
456 | } | ||
457 | |||
458 | priv->abs_dev = abs_dev; | ||
459 | psmouse->private = priv; | ||
460 | |||
461 | input_set_capability(rel_dev, EV_REL, REL_WHEEL); | ||
462 | |||
463 | /* Set up and register absolute device */ | ||
464 | snprintf(priv->phys, sizeof(priv->phys), "%s/input1", | ||
465 | psmouse->ps2dev.serio->phys); | ||
466 | |||
467 | /* Mimic name setup for relative device in psmouse-base.c */ | ||
468 | snprintf(priv->dev_name, sizeof(priv->dev_name), "%s %s %s", | ||
469 | VMMOUSE_PSNAME, VMMOUSE_VENDOR, VMMOUSE_NAME); | ||
470 | abs_dev->phys = priv->phys; | ||
471 | abs_dev->name = priv->dev_name; | ||
472 | abs_dev->id.bustype = BUS_I8042; | ||
473 | abs_dev->id.vendor = 0x0002; | ||
474 | abs_dev->id.product = PSMOUSE_VMMOUSE; | ||
475 | abs_dev->id.version = psmouse->model; | ||
476 | abs_dev->dev.parent = &psmouse->ps2dev.serio->dev; | ||
477 | |||
478 | error = input_register_device(priv->abs_dev); | ||
479 | if (error) | ||
480 | goto init_fail; | ||
481 | |||
482 | /* Set absolute device capabilities */ | ||
483 | input_set_capability(abs_dev, EV_KEY, BTN_LEFT); | ||
484 | input_set_capability(abs_dev, EV_KEY, BTN_RIGHT); | ||
485 | input_set_capability(abs_dev, EV_KEY, BTN_MIDDLE); | ||
486 | input_set_capability(abs_dev, EV_ABS, ABS_X); | ||
487 | input_set_capability(abs_dev, EV_ABS, ABS_Y); | ||
488 | input_set_abs_params(abs_dev, ABS_X, 0, VMMOUSE_MAX_X, 0, 0); | ||
489 | input_set_abs_params(abs_dev, ABS_Y, 0, VMMOUSE_MAX_Y, 0, 0); | ||
490 | |||
491 | psmouse->protocol_handler = vmmouse_process_byte; | ||
492 | psmouse->disconnect = vmmouse_disconnect; | ||
493 | psmouse->reconnect = vmmouse_reconnect; | ||
494 | |||
495 | return 0; | ||
496 | |||
497 | init_fail: | ||
498 | vmmouse_disable(psmouse); | ||
499 | psmouse_reset(psmouse); | ||
500 | input_free_device(abs_dev); | ||
501 | kfree(priv); | ||
502 | psmouse->private = NULL; | ||
503 | |||
504 | release_region: | ||
505 | release_region(VMMOUSE_PROTO_PORT, 4); | ||
506 | |||
507 | return error; | ||
508 | } | ||
diff --git a/drivers/input/mouse/vmmouse.h b/drivers/input/mouse/vmmouse.h new file mode 100644 index 000000000000..6f126017a24c --- /dev/null +++ b/drivers/input/mouse/vmmouse.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors. | ||
3 | * | ||
4 | * Copyright (C) 2014, VMware, Inc. All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _VMMOUSE_H | ||
12 | #define _VMMOUSE_H | ||
13 | |||
14 | #ifdef CONFIG_MOUSE_PS2_VMMOUSE | ||
15 | #define VMMOUSE_PSNAME "VirtualPS/2" | ||
16 | |||
17 | int vmmouse_detect(struct psmouse *psmouse, bool set_properties); | ||
18 | int vmmouse_init(struct psmouse *psmouse); | ||
19 | #else | ||
20 | static inline int vmmouse_detect(struct psmouse *psmouse, bool set_properties) | ||
21 | { | ||
22 | return -ENOSYS; | ||
23 | } | ||
24 | static inline int vmmouse_init(struct psmouse *psmouse) | ||
25 | { | ||
26 | return -ENOSYS; | ||
27 | } | ||
28 | #endif | ||
29 | |||
30 | #endif | ||
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 2875ddf37289..40b98dda8f38 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
@@ -14,6 +14,8 @@ | |||
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/acpi.h> | ||
18 | #include <linux/dmi.h> | ||
17 | #include <linux/module.h> | 19 | #include <linux/module.h> |
18 | #include <linux/init.h> | 20 | #include <linux/init.h> |
19 | #include <linux/completion.h> | 21 | #include <linux/completion.h> |
@@ -2371,7 +2373,7 @@ static void mxt_input_close(struct input_dev *dev) | |||
2371 | } | 2373 | } |
2372 | 2374 | ||
2373 | #ifdef CONFIG_OF | 2375 | #ifdef CONFIG_OF |
2374 | static struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) | 2376 | static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) |
2375 | { | 2377 | { |
2376 | struct mxt_platform_data *pdata; | 2378 | struct mxt_platform_data *pdata; |
2377 | u32 *keymap; | 2379 | u32 *keymap; |
@@ -2379,7 +2381,7 @@ static struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) | |||
2379 | int proplen, i, ret; | 2381 | int proplen, i, ret; |
2380 | 2382 | ||
2381 | if (!client->dev.of_node) | 2383 | if (!client->dev.of_node) |
2382 | return ERR_PTR(-ENODEV); | 2384 | return ERR_PTR(-ENOENT); |
2383 | 2385 | ||
2384 | pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); | 2386 | pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); |
2385 | if (!pdata) | 2387 | if (!pdata) |
@@ -2410,25 +2412,132 @@ static struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) | |||
2410 | return pdata; | 2412 | return pdata; |
2411 | } | 2413 | } |
2412 | #else | 2414 | #else |
2413 | static struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) | 2415 | static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) |
2414 | { | 2416 | { |
2415 | dev_dbg(&client->dev, "No platform data specified\n"); | 2417 | return ERR_PTR(-ENOENT); |
2416 | return ERR_PTR(-EINVAL); | 2418 | } |
2419 | #endif | ||
2420 | |||
2421 | #ifdef CONFIG_ACPI | ||
2422 | |||
2423 | struct mxt_acpi_platform_data { | ||
2424 | const char *hid; | ||
2425 | struct mxt_platform_data pdata; | ||
2426 | }; | ||
2427 | |||
2428 | static unsigned int samus_touchpad_buttons[] = { | ||
2429 | KEY_RESERVED, | ||
2430 | KEY_RESERVED, | ||
2431 | KEY_RESERVED, | ||
2432 | BTN_LEFT | ||
2433 | }; | ||
2434 | |||
2435 | static struct mxt_acpi_platform_data samus_platform_data[] = { | ||
2436 | { | ||
2437 | /* Touchpad */ | ||
2438 | .hid = "ATML0000", | ||
2439 | .pdata = { | ||
2440 | .t19_num_keys = ARRAY_SIZE(samus_touchpad_buttons), | ||
2441 | .t19_keymap = samus_touchpad_buttons, | ||
2442 | }, | ||
2443 | }, | ||
2444 | { | ||
2445 | /* Touchscreen */ | ||
2446 | .hid = "ATML0001", | ||
2447 | }, | ||
2448 | { } | ||
2449 | }; | ||
2450 | |||
2451 | static const struct dmi_system_id mxt_dmi_table[] = { | ||
2452 | { | ||
2453 | /* 2015 Google Pixel */ | ||
2454 | .ident = "Chromebook Pixel 2", | ||
2455 | .matches = { | ||
2456 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), | ||
2457 | DMI_MATCH(DMI_PRODUCT_NAME, "Samus"), | ||
2458 | }, | ||
2459 | .driver_data = samus_platform_data, | ||
2460 | }, | ||
2461 | { } | ||
2462 | }; | ||
2463 | |||
2464 | static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client) | ||
2465 | { | ||
2466 | struct acpi_device *adev; | ||
2467 | const struct dmi_system_id *system_id; | ||
2468 | const struct mxt_acpi_platform_data *acpi_pdata; | ||
2469 | |||
2470 | /* | ||
2471 | * Ignore ACPI devices representing bootloader mode. | ||
2472 | * | ||
2473 | * This is a bit of a hack: Google Chromebook BIOS creates ACPI | ||
2474 | * devices for both application and bootloader modes, but we are | ||
2475 | * interested in application mode only (if device is in bootloader | ||
2476 | * mode we'll end up switching into application anyway). So far | ||
2477 | * application mode addresses were all above 0x40, so we'll use it | ||
2478 | * as a threshold. | ||
2479 | */ | ||
2480 | if (client->addr < 0x40) | ||
2481 | return ERR_PTR(-ENXIO); | ||
2482 | |||
2483 | adev = ACPI_COMPANION(&client->dev); | ||
2484 | if (!adev) | ||
2485 | return ERR_PTR(-ENOENT); | ||
2486 | |||
2487 | system_id = dmi_first_match(mxt_dmi_table); | ||
2488 | if (!system_id) | ||
2489 | return ERR_PTR(-ENOENT); | ||
2490 | |||
2491 | acpi_pdata = system_id->driver_data; | ||
2492 | if (!acpi_pdata) | ||
2493 | return ERR_PTR(-ENOENT); | ||
2494 | |||
2495 | while (acpi_pdata->hid) { | ||
2496 | if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid)) | ||
2497 | return &acpi_pdata->pdata; | ||
2498 | |||
2499 | acpi_pdata++; | ||
2500 | } | ||
2501 | |||
2502 | return ERR_PTR(-ENOENT); | ||
2503 | } | ||
2504 | #else | ||
2505 | static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client) | ||
2506 | { | ||
2507 | return ERR_PTR(-ENOENT); | ||
2417 | } | 2508 | } |
2418 | #endif | 2509 | #endif |
2419 | 2510 | ||
2511 | static const struct mxt_platform_data * | ||
2512 | mxt_get_platform_data(struct i2c_client *client) | ||
2513 | { | ||
2514 | const struct mxt_platform_data *pdata; | ||
2515 | |||
2516 | pdata = dev_get_platdata(&client->dev); | ||
2517 | if (pdata) | ||
2518 | return pdata; | ||
2519 | |||
2520 | pdata = mxt_parse_dt(client); | ||
2521 | if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT) | ||
2522 | return pdata; | ||
2523 | |||
2524 | pdata = mxt_parse_acpi(client); | ||
2525 | if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT) | ||
2526 | return pdata; | ||
2527 | |||
2528 | dev_err(&client->dev, "No platform data specified\n"); | ||
2529 | return ERR_PTR(-EINVAL); | ||
2530 | } | ||
2531 | |||
2420 | static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) | 2532 | static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) |
2421 | { | 2533 | { |
2422 | struct mxt_data *data; | 2534 | struct mxt_data *data; |
2423 | const struct mxt_platform_data *pdata; | 2535 | const struct mxt_platform_data *pdata; |
2424 | int error; | 2536 | int error; |
2425 | 2537 | ||
2426 | pdata = dev_get_platdata(&client->dev); | 2538 | pdata = mxt_get_platform_data(client); |
2427 | if (!pdata) { | 2539 | if (IS_ERR(pdata)) |
2428 | pdata = mxt_parse_dt(client); | 2540 | return PTR_ERR(pdata); |
2429 | if (IS_ERR(pdata)) | ||
2430 | return PTR_ERR(pdata); | ||
2431 | } | ||
2432 | 2541 | ||
2433 | data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); | 2542 | data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); |
2434 | if (!data) { | 2543 | if (!data) { |
@@ -2536,6 +2645,15 @@ static const struct of_device_id mxt_of_match[] = { | |||
2536 | }; | 2645 | }; |
2537 | MODULE_DEVICE_TABLE(of, mxt_of_match); | 2646 | MODULE_DEVICE_TABLE(of, mxt_of_match); |
2538 | 2647 | ||
2648 | #ifdef CONFIG_ACPI | ||
2649 | static const struct acpi_device_id mxt_acpi_id[] = { | ||
2650 | { "ATML0000", 0 }, /* Touchpad */ | ||
2651 | { "ATML0001", 0 }, /* Touchscreen */ | ||
2652 | { } | ||
2653 | }; | ||
2654 | MODULE_DEVICE_TABLE(acpi, mxt_acpi_id); | ||
2655 | #endif | ||
2656 | |||
2539 | static const struct i2c_device_id mxt_id[] = { | 2657 | static const struct i2c_device_id mxt_id[] = { |
2540 | { "qt602240_ts", 0 }, | 2658 | { "qt602240_ts", 0 }, |
2541 | { "atmel_mxt_ts", 0 }, | 2659 | { "atmel_mxt_ts", 0 }, |
@@ -2550,6 +2668,7 @@ static struct i2c_driver mxt_driver = { | |||
2550 | .name = "atmel_mxt_ts", | 2668 | .name = "atmel_mxt_ts", |
2551 | .owner = THIS_MODULE, | 2669 | .owner = THIS_MODULE, |
2552 | .of_match_table = of_match_ptr(mxt_of_match), | 2670 | .of_match_table = of_match_ptr(mxt_of_match), |
2671 | .acpi_match_table = ACPI_PTR(mxt_acpi_id), | ||
2553 | .pm = &mxt_pm_ops, | 2672 | .pm = &mxt_pm_ops, |
2554 | }, | 2673 | }, |
2555 | .probe = mxt_probe, | 2674 | .probe = mxt_probe, |
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 43b3c9c2d788..0efd766a545b 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c | |||
@@ -699,7 +699,7 @@ static int elants_i2c_fw_update(struct elants_data *ts) | |||
699 | char *fw_name; | 699 | char *fw_name; |
700 | int error; | 700 | int error; |
701 | 701 | ||
702 | fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%4x.bin", ts->hw_version); | 702 | fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); |
703 | if (!fw_name) | 703 | if (!fw_name) |
704 | return -ENOMEM; | 704 | return -ENOMEM; |
705 | 705 | ||