diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-04-21 14:12:42 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-04-21 14:12:42 -0400 |
commit | 48853389f206b689260ddfd3006816779ca7a52a (patch) | |
tree | 8abc3be612779c3252190bc54a38eb0b3c258e19 /drivers/input/mouse | |
parent | 85a3685852d9ac7d92be9d824533c915a4597fa4 (diff) | |
parent | c9eeb5084b27ffede2709e8775827729d0c7c46c (diff) |
Merge branch 'next' into for-linus
Prepare second round of updates for 4.1 merge window.
Diffstat (limited to 'drivers/input/mouse')
-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 |
11 files changed, 634 insertions, 19 deletions
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 | ||