From 09c398bc01f507e31b9c1325a10e231d271fea00 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 7 Mar 2017 09:41:34 -0800 Subject: Input: alps - move ALPS_PROTO_V4 out of alps_model_data table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like for other protocols create alps_v4_protocol_data and use it in alps_identify() function. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 72b28ebfe360..f36de829390b 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -138,7 +138,6 @@ static const struct alps_model_info alps_model_data[] = { { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */ - { { 0x73, 0x02, 0x64 }, 0x8a, { ALPS_PROTO_V4, 0x8f, 0x8f, 0 } }, }; static const struct alps_protocol_info alps_v3_protocol_data = { @@ -149,6 +148,10 @@ static const struct alps_protocol_info alps_v3_rushmore_data = { ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT }; +static const struct alps_protocol_info alps_v4_protocol_data = { + ALPS_PROTO_V4, 0x8f, 0x8f, 0 +}; + static const struct alps_protocol_info alps_v5_protocol_data = { ALPS_PROTO_V5, 0xc8, 0xd8, 0 }; @@ -2815,7 +2818,10 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) protocol = alps_match_table(e7, ec); if (!protocol) { - if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && + if (e7[0] == 0x73 && e7[1] == 0x02 && e7[2] == 0x64 && + ec[2] == 0x8a) { + protocol = &alps_v4_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { protocol = &alps_v5_protocol_data; } else if (ec[0] == 0x88 && -- cgit From c9815232c3cca58bb2b664f37b681841981ed4a9 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 7 Mar 2017 09:42:46 -0800 Subject: Input: alps - warn about unsupported ALPS V9 touchpad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for devices with ALPS_PROTO_V9 is not implemented yet but we can detect these alps touchpads and warn users about it. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 10 ++++++++++ drivers/input/mouse/alps.h | 1 + 2 files changed, 11 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f36de829390b..c893af6a33b0 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -164,6 +164,10 @@ static const struct alps_protocol_info alps_v8_protocol_data = { ALPS_PROTO_V8, 0x18, 0x18, 0 }; +static const struct alps_protocol_info alps_v9_protocol_data = { + ALPS_PROTO_V9, 0xc8, 0xc8, 0 +}; + /* * Some v2 models report the stick buttons in separate bits */ @@ -2838,6 +2842,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x28 && ec[1] == 0x01) { protocol = &alps_v8_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0xc8) { + protocol = &alps_v9_protocol_data; + psmouse_warn(psmouse, + "Unsupported ALPS V9 touchpad: E7=%3ph, EC=%3ph\n", + e7, ec); + return -EINVAL; } else { psmouse_dbg(psmouse, "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 6d279aa27cb9..54f9f4401a77 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -23,6 +23,7 @@ #define ALPS_PROTO_V6 0x600 #define ALPS_PROTO_V7 0x700 /* t3btl t4s */ #define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */ +#define ALPS_PROTO_V9 0x900 /* ss3btl */ #define MAX_TOUCHES 4 -- cgit From a3cbfd56ff909393e2d59236d94205ae17dfc5d5 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 7 Mar 2017 09:43:35 -0800 Subject: Input: alps - cleanup alps_model_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sort all devices in alps_model_data by signature and remove command_mode_resp which is not used anymore. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 56 +++++++++++++++++++++------------------------- drivers/input/mouse/alps.h | 5 ----- 2 files changed, 25 insertions(+), 36 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index c893af6a33b0..e761955978c6 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -106,38 +106,36 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { #define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ static const struct alps_model_info alps_model_data[] = { - { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ - { { 0x33, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ - { { 0x53, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x53, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x60, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ - { { 0x63, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x28 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ - { { 0x63, 0x02, 0x3c }, 0x00, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ - { { 0x63, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ - { { 0x63, 0x02, 0x64 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ - { { 0x73, 0x00, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ - { { 0x73, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x73, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ - /* * XXX This entry is suspicious. First byte has zero lower nibble, * which is what a normal mouse would report. Also, the value 0x0e * isn't valid per PS/2 spec. */ - { { 0x20, 0x02, 0x0e }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - - { { 0x22, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - { { 0x22, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ - /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ - { { 0x62, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, - { { 0x73, 0x00, 0x14 }, 0x00, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ - { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ - { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, + { { 0x20, 0x02, 0x0e }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + + { { 0x22, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + { { 0x22, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ + { { 0x32, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ + { { 0x33, 0x02, 0x0a }, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ + { { 0x52, 0x01, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */ + { { 0x53, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x53, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x60, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ + { { 0x62, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xcf, 0xcf, + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ + { { 0x63, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x28 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ + { { 0x63, 0x02, 0x3c }, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ + { { 0x63, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ + { { 0x63, 0x02, 0x64 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ + { { 0x73, 0x00, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ + { { 0x73, 0x00, 0x14 }, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ + { { 0x73, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x73, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ + { { 0x73, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ }; static const struct alps_protocol_info alps_v3_protocol_data = { @@ -2779,12 +2777,8 @@ static const struct alps_protocol_info *alps_match_table(unsigned char *e7, for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { model = &alps_model_data[i]; - if (!memcmp(e7, model->signature, sizeof(model->signature)) && - (!model->command_mode_resp || - model->command_mode_resp == ec[2])) { - + if (!memcmp(e7, model->signature, sizeof(model->signature))) return &model->protocol_info; - } } return NULL; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 54f9f4401a77..dea31638c91f 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -163,10 +163,6 @@ struct alps_protocol_info { /** * struct alps_model_info - touchpad ID table * @signature: E7 response string to match. - * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response - * (aka command mode response) identifies the firmware minor version. This - * can be used to distinguish different hardware models which are not - * uniquely identifiable through their E7 responses. * @protocol_info: information about protocol used by the device. * * Many (but not all) ALPS touchpads can be identified by looking at the @@ -175,7 +171,6 @@ struct alps_protocol_info { */ struct alps_model_info { u8 signature[3]; - u8 command_mode_resp; struct alps_protocol_info protocol_info; }; -- cgit From 72bf60f19661e0451071f6a2f1940f9af1a3e33b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Mar 2017 13:31:50 -0700 Subject: Input: synaptics_i2c - add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index cb2bf203f4ca..8538318d332c 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -652,9 +652,18 @@ static const struct i2c_device_id synaptics_i2c_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); +#ifdef CONFIG_OF +static const struct of_device_id synaptics_i2c_of_match[] = { + { .compatible = "synaptics,synaptics_i2c", }, + { }, +}; +MODULE_DEVICE_TABLE(of, synaptics_i2c_of_match); +#endif + static struct i2c_driver synaptics_i2c_driver = { .driver = { .name = DRIVER_NAME, + .of_match_table = of_match_ptr(synaptics_i2c_of_match), .pm = &synaptics_i2c_pm, }, -- cgit From 996b9eedd061752bfa0f3a10381515d67db26b3e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 10:02:50 -0700 Subject: Input: synaptics - do not mix logical and bitwise operations Let's stop using !!x to reduce value of trackstick button expression to 0/1 and use shift instead. This removes the following sparse warning: CHECK drivers/input/mouse/synaptics.c drivers/input/mouse/synaptics.c:943:79: warning: dubious: !x | y Also, the bits we are testing are not capabilities, so lets drop "_CAP" suffix from macro names. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 6 +++--- drivers/input/mouse/synaptics.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 597ee4b01d9f..6a23c21968c1 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -884,9 +884,9 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, u8 pt_buttons; /* The trackstick expects at most 3 buttons */ - pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons) | - SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 | - SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2; + pt_buttons = SYN_EXT_BUTTON_STICK_L(hw->ext_buttons) | + SYN_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 | + SYN_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2; serio_interrupt(priv->pt_port, PSMOUSE_OOB_EXTRA_BTNS, SERIO_OOB_DATA); diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 116ae2546ace..b76bb7a38472 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -111,9 +111,9 @@ #define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000) #define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000) -#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01)) -#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02)) -#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04)) +#define SYN_EXT_BUTTON_STICK_L(eb) (((eb) & BIT(0)) >> 0) +#define SYN_EXT_BUTTON_STICK_M(eb) (((eb) & BIT(1)) >> 1) +#define SYN_EXT_BUTTON_STICK_R(eb) (((eb) & BIT(2)) >> 2) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) -- cgit From 0ab3fa57425023f42e8822a293d9b87a3ad4e2b3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Mar 2017 23:19:22 -0800 Subject: Input: psmouse - implement fast reconnect option Make use of serio's fast reconnect option and allow psmouse protocol handler's to implement fast reconnect handlers that will be called during system resume. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 30 +++++++++++++++++++++++++++--- drivers/input/mouse/psmouse.h | 1 + 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a598b7223cef..47fd2976da7f 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -966,6 +966,7 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) psmouse->protocol_handler = psmouse_process_byte; psmouse->pktsize = 3; psmouse->reconnect = NULL; + psmouse->fast_reconnect = NULL; psmouse->disconnect = NULL; psmouse->cleanup = NULL; psmouse->pt_activate = NULL; @@ -1628,15 +1629,26 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) goto out; } -static int psmouse_reconnect(struct serio *serio) +static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) { struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *parent = NULL; + int (*reconnect_handler)(struct psmouse *); unsigned char type; int rc = -1; mutex_lock(&psmouse_mutex); + if (fast_reconnect) { + reconnect_handler = psmouse->fast_reconnect; + if (!reconnect_handler) { + rc = -ENOENT; + goto out_unlock; + } + } else { + reconnect_handler = psmouse->reconnect; + } + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); psmouse_deactivate(parent); @@ -1644,8 +1656,8 @@ static int psmouse_reconnect(struct serio *serio) psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - if (psmouse->reconnect) { - if (psmouse->reconnect(psmouse)) + if (reconnect_handler) { + if (reconnect_handler(psmouse)) goto out; } else { psmouse_reset(psmouse); @@ -1677,10 +1689,21 @@ out: if (parent) psmouse_activate(parent); +out_unlock: mutex_unlock(&psmouse_mutex); return rc; } +static int psmouse_reconnect(struct serio *serio) +{ + return __psmouse_reconnect(serio, false); +} + +static int psmouse_fast_reconnect(struct serio *serio) +{ + return __psmouse_reconnect(serio, true); +} + static struct serio_device_id psmouse_serio_ids[] = { { .type = SERIO_8042, @@ -1708,6 +1731,7 @@ static struct serio_driver psmouse_drv = { .interrupt = psmouse_interrupt, .connect = psmouse_connect, .reconnect = psmouse_reconnect, + .fast_reconnect = psmouse_fast_reconnect, .disconnect = psmouse_disconnect, .cleanup = psmouse_cleanup, }; diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 8c83b8e2505c..bc76e771812b 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -80,6 +80,7 @@ struct psmouse { void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale); int (*reconnect)(struct psmouse *psmouse); + int (*fast_reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); void (*cleanup)(struct psmouse *psmouse); int (*poll)(struct psmouse *psmouse); -- cgit From 085fa80dfdd60ac58137a5b5d231e70456126fda Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 3 Mar 2017 15:29:00 -0800 Subject: Input: psmouse - store pointer to current protocol Instead of storing only protocol "type" in pmsouse structure, store pointer to the protocol structure, so that we have access to more data without having to copy it over to psmouse structure. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 43 +++++++++-------------- drivers/input/mouse/psmouse.h | 70 ++++++++++++++++++++++---------------- 2 files changed, 58 insertions(+), 55 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 47fd2976da7f..bb5d164849ea 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -116,17 +116,6 @@ static DEFINE_MUTEX(psmouse_mutex); static struct workqueue_struct *kpsmoused_wq; -struct psmouse_protocol { - enum psmouse_type type; - bool maxproto; - bool ignore_parity; /* Protocol should ignore parity errors from KBC */ - bool try_passthru; /* Try protocol also on passthrough ports */ - const char *name; - const char *alias; - int (*detect)(struct psmouse *, bool); - int (*init)(struct psmouse *); -}; - static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons) { input_report_key(dev, BTN_LEFT, buttons & BIT(0)); @@ -148,7 +137,7 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) /* Full packet accumulated, process it */ - switch (psmouse->type) { + switch (psmouse->protocol->type) { case PSMOUSE_IMPS: /* IntelliMouse has scroll wheel */ input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); @@ -325,7 +314,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; if (unlikely((flags & SERIO_TIMEOUT) || - ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) { + ((flags & SERIO_PARITY) && + !psmouse->protocol->ignore_parity))) { if (psmouse->state == PSMOUSE_ACTIVATED) psmouse_warn(psmouse, @@ -372,7 +362,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, } if (psmouse->packet[1] == PSMOUSE_RET_ID || - (psmouse->type == PSMOUSE_HGPK && + (psmouse->protocol->type == PSMOUSE_HGPK && psmouse->packet[1] == PSMOUSE_RET_BAT)) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); serio_reconnect(serio); @@ -959,6 +949,8 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + psmouse->protocol = &psmouse_protocols[0]; + psmouse->set_rate = psmouse_set_rate; psmouse->set_resolution = psmouse_set_resolution; psmouse->set_scale = psmouse_set_scale; @@ -1476,6 +1468,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, { const struct psmouse_protocol *selected_proto; struct input_dev *input_dev = psmouse->dev; + enum psmouse_type type; input_dev->dev.parent = &psmouse->ps2dev.serio->dev; @@ -1488,15 +1481,13 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, if (proto->init && proto->init(psmouse) < 0) return -1; - psmouse->type = proto->type; selected_proto = proto; } else { - psmouse->type = psmouse_extensions(psmouse, - psmouse_max_proto, true); - selected_proto = psmouse_protocol_by_type(psmouse->type); + type = psmouse_extensions(psmouse, psmouse_max_proto, true); + selected_proto = psmouse_protocol_by_type(type); } - psmouse->ignore_parity = selected_proto->ignore_parity; + psmouse->protocol = selected_proto; /* * If mouse's packet size is 3 there is no point in polling the @@ -1522,7 +1513,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, input_dev->phys = psmouse->phys; input_dev->id.bustype = BUS_I8042; input_dev->id.vendor = 0x0002; - input_dev->id.product = psmouse->type; + input_dev->id.product = psmouse->protocol->type; input_dev->id.version = psmouse->model; return 0; @@ -1634,7 +1625,7 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *parent = NULL; int (*reconnect_handler)(struct psmouse *); - unsigned char type; + enum psmouse_type type; int rc = -1; mutex_lock(&psmouse_mutex); @@ -1666,7 +1657,7 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) goto out; type = psmouse_extensions(psmouse, psmouse_max_proto, false); - if (psmouse->type != type) + if (psmouse->protocol->type != type) goto out; } @@ -1816,7 +1807,7 @@ static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf) { - return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); + return sprintf(buf, "%s\n", psmouse->protocol->name); } static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count) @@ -1832,7 +1823,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (!proto) return -EINVAL; - if (psmouse->type == proto->type) + if (psmouse->protocol == proto) return count; new_dev = input_allocate_device(); @@ -1856,7 +1847,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co return -ENODEV; } - if (psmouse->type == proto->type) { + if (psmouse->protocol == proto) { input_free_device(new_dev); return count; /* switched by other thread */ } @@ -1869,7 +1860,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co } old_dev = psmouse->dev; - old_proto = psmouse_protocol_by_type(psmouse->type); + old_proto = psmouse->protocol; if (psmouse->disconnect) psmouse->disconnect(psmouse); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index bc76e771812b..36bd42179456 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -44,21 +44,58 @@ enum psmouse_scale { PSMOUSE_SCALE21 }; +enum psmouse_type { + PSMOUSE_NONE, + PSMOUSE_PS2, + PSMOUSE_PS2PP, + PSMOUSE_THINKPS, + PSMOUSE_GENPS, + PSMOUSE_IMPS, + PSMOUSE_IMEX, + PSMOUSE_SYNAPTICS, + PSMOUSE_ALPS, + PSMOUSE_LIFEBOOK, + PSMOUSE_TRACKPOINT, + PSMOUSE_TOUCHKIT_PS2, + PSMOUSE_CORTRON, + PSMOUSE_HGPK, + PSMOUSE_ELANTECH, + PSMOUSE_FSP, + PSMOUSE_SYNAPTICS_RELATIVE, + PSMOUSE_CYPRESS, + PSMOUSE_FOCALTECH, + PSMOUSE_VMMOUSE, + PSMOUSE_BYD, + PSMOUSE_AUTO /* This one should always be last */ +}; + +struct psmouse; + +struct psmouse_protocol { + enum psmouse_type type; + bool maxproto; + bool ignore_parity; /* Protocol should ignore parity errors from KBC */ + bool try_passthru; /* Try protocol also on passthrough ports */ + const char *name; + const char *alias; + int (*detect)(struct psmouse *, bool); + int (*init)(struct psmouse *); +}; + struct psmouse { void *private; struct input_dev *dev; struct ps2dev ps2dev; struct delayed_work resync_work; - char *vendor; - char *name; + const char *vendor; + const char *name; + const struct psmouse_protocol *protocol; unsigned char packet[8]; unsigned char badbyte; unsigned char pktcnt; unsigned char pktsize; - unsigned char type; unsigned char oob_data_type; unsigned char extra_buttons; - bool ignore_parity; bool acks_disable_command; unsigned int model; unsigned long last; @@ -89,31 +126,6 @@ struct psmouse { void (*pt_deactivate)(struct psmouse *psmouse); }; -enum psmouse_type { - PSMOUSE_NONE, - PSMOUSE_PS2, - PSMOUSE_PS2PP, - PSMOUSE_THINKPS, - PSMOUSE_GENPS, - PSMOUSE_IMPS, - PSMOUSE_IMEX, - PSMOUSE_SYNAPTICS, - PSMOUSE_ALPS, - PSMOUSE_LIFEBOOK, - PSMOUSE_TRACKPOINT, - PSMOUSE_TOUCHKIT_PS2, - PSMOUSE_CORTRON, - PSMOUSE_HGPK, - PSMOUSE_ELANTECH, - PSMOUSE_FSP, - PSMOUSE_SYNAPTICS_RELATIVE, - PSMOUSE_CYPRESS, - PSMOUSE_FOCALTECH, - PSMOUSE_VMMOUSE, - PSMOUSE_BYD, - PSMOUSE_AUTO /* This one should always be last */ -}; - void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, unsigned long delay); int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); -- cgit From c774326a219536ab615d68a22875673f6f608b62 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 2 Mar 2017 15:50:56 -0800 Subject: Input: psmouse - introduce notion of SMBus companions Prepare PS/2 mouse drivers to work with devices that are accessible both via PS/2 and SMBus, which provides higher bandwidth, and thus suits better for modern multi-touch devices. We expect that SMBus drivers will take control over the device, so when we detect SMBus "protocol" we forego registering input device, or enabling PS/2 device reports (as it usually makes device unresponsive to access over SMBus). Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 103 +++++++++++++++++++++++++------------ drivers/input/mouse/psmouse.h | 1 + 2 files changed, 71 insertions(+), 33 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index bb5d164849ea..a84f8ed2ba5d 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1424,9 +1424,8 @@ static void psmouse_cleanup(struct serio *serio) */ static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse, *parent = NULL; - - psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *parent = NULL; sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group); @@ -1454,7 +1453,10 @@ static void psmouse_disconnect(struct serio *serio) serio_close(serio); serio_set_drvdata(serio, NULL); - input_unregister_device(psmouse->dev); + + if (psmouse->dev) + input_unregister_device(psmouse->dev); + kfree(psmouse); if (parent) @@ -1575,12 +1577,18 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_switch_protocol(psmouse, NULL); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - psmouse_initialize(psmouse); + if (!psmouse->protocol->smbus_companion) { + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); - error = input_register_device(psmouse->dev); - if (error) - goto err_protocol_disconnect; + error = input_register_device(input_dev); + if (error) + goto err_protocol_disconnect; + } else { + /* Smbus companion will be reporting events, not us. */ + input_free_device(input_dev); + psmouse->dev = input_dev = NULL; + } if (parent && parent->pt_activate) parent->pt_activate(parent); @@ -1589,7 +1597,12 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (error) goto err_pt_deactivate; - psmouse_activate(psmouse); + /* + * PS/2 devices having SMBus companions should stay disabled + * on PS/2 side, in order to have SMBus part operable. + */ + if (!psmouse->protocol->smbus_companion) + psmouse_activate(psmouse); out: /* If this is a pass-through port the parent needs to be re-activated */ @@ -1602,8 +1615,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) err_pt_deactivate: if (parent && parent->pt_deactivate) parent->pt_deactivate(parent); - input_unregister_device(psmouse->dev); - input_dev = NULL; /* so we don't try to free it below */ + if (input_dev) { + input_unregister_device(input_dev); + input_dev = NULL; /* so we don't try to free it below */ + } err_protocol_disconnect: if (psmouse->disconnect) psmouse->disconnect(psmouse); @@ -1665,14 +1680,21 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) * OK, the device type (and capabilities) match the old one, * we can continue using it, complete initialization */ - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - psmouse_initialize(psmouse); + if (!psmouse->protocol->smbus_companion) { + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); + } if (parent && parent->pt_activate) parent->pt_activate(parent); - psmouse_activate(psmouse); + /* + * PS/2 devices having SMBus companions should stay disabled + * on PS/2 side, in order to have SMBus part operable. + */ + if (!psmouse->protocol->smbus_companion) + psmouse_activate(psmouse); + rc = 0; out: @@ -1732,9 +1754,11 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de { struct serio *serio = to_serio_port(dev); struct psmouse_attribute *attr = to_psmouse_attr(devattr); - struct psmouse *psmouse; + struct psmouse *psmouse = serio_get_drvdata(serio); - psmouse = serio_get_drvdata(serio); + if (psmouse->protocol->smbus_companion && + devattr != &psmouse_attr_protocol.dattr) + return -ENOENT; return attr->show(psmouse, attr->data, buf); } @@ -1753,6 +1777,12 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev psmouse = serio_get_drvdata(serio); + if (psmouse->protocol->smbus_companion && + devattr != &psmouse_attr_protocol.dattr) { + retval = -ENOENT; + goto out_unlock; + } + if (attr->protect) { if (psmouse->state == PSMOUSE_IGNORE) { retval = -ENODEV; @@ -1764,13 +1794,14 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev psmouse_deactivate(parent); } - psmouse_deactivate(psmouse); + if (!psmouse->protocol->smbus_companion) + psmouse_deactivate(psmouse); } retval = attr->set(psmouse, attr->data, buf, count); if (attr->protect) { - if (retval != -ENODEV) + if (retval != -ENODEV && !psmouse->protocol->smbus_companion) psmouse_activate(psmouse); if (parent) @@ -1879,23 +1910,29 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co psmouse_initialize(psmouse); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - error = input_register_device(psmouse->dev); - if (error) { - if (psmouse->disconnect) - psmouse->disconnect(psmouse); + if (psmouse->protocol->smbus_companion) { + input_free_device(psmouse->dev); + psmouse->dev = NULL; + } else { + error = input_register_device(psmouse->dev); + if (error) { + if (psmouse->disconnect) + psmouse->disconnect(psmouse); - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_free_device(new_dev); - psmouse->dev = old_dev; - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - psmouse_switch_protocol(psmouse, old_proto); - psmouse_initialize(psmouse); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_set_state(psmouse, PSMOUSE_IGNORE); + input_free_device(new_dev); + psmouse->dev = old_dev; + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); + psmouse_switch_protocol(psmouse, old_proto); + psmouse_initialize(psmouse); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - return error; + return error; + } } - input_unregister_device(old_dev); + if (old_dev) + input_unregister_device(old_dev); if (parent && parent->pt_activate) parent->pt_activate(parent); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 36bd42179456..e853dee05e79 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -76,6 +76,7 @@ struct psmouse_protocol { bool maxproto; bool ignore_parity; /* Protocol should ignore parity errors from KBC */ bool try_passthru; /* Try protocol also on passthrough ports */ + bool smbus_companion; /* "Protocol" is a stub, device is on SMBus */ const char *name; const char *alias; int (*detect)(struct psmouse *, bool); -- cgit From 8eb92e5c91338eb19f86ffb2232258337ebf905b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Mar 2017 10:48:23 -0800 Subject: Input: psmouse - add support for SMBus companions This provides glue between PS/2 devices that enumerate the RMI4 devices and Elan touchpads to the RMI4 (or Elan) SMBus driver. The SMBus devices keep their PS/2 connection alive. If the initialization process goes too far (psmouse_activate called), the device disconnects from the I2C bus and stays on the PS/2 bus, that is why we explicitly disable PS/2 device reporting (by calling psmouse_deactivate) before trying to register SMBus companion device. The HID over I2C devices are enumerated through the ACPI DSDT, and their PS/2 device also exports the InterTouch bit in the extended capability 0x0C. However, the firmware keeps its I2C connection open even after going further in the PS/2 initialization. We don't need to take extra precautions with those device, especially because they block their PS/2 communication when HID over I2C is used. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 4 + drivers/input/mouse/Makefile | 2 + drivers/input/mouse/psmouse-base.c | 16 +- drivers/input/mouse/psmouse-smbus.c | 294 ++++++++++++++++++++++++++++++++++++ drivers/input/mouse/psmouse.h | 29 ++++ 5 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 drivers/input/mouse/psmouse-smbus.c (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 096abb4ad5cd..87bde8a210c7 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -171,6 +171,10 @@ config MOUSE_PS2_VMMOUSE If unsure, say N. +config MOUSE_PS2_SMBUS + bool + depends on MOUSE_PS2 + config MOUSE_SERIAL tristate "Serial mouse" select SERIO diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 6168b134937b..56bf0ad877c6 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -39,6 +39,8 @@ psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o psmouse-$(CONFIG_MOUSE_PS2_VMMOUSE) += vmmouse.o +psmouse-$(CONFIG_MOUSE_PS2_SMBUS) += psmouse-smbus.o + elan_i2c-objs := elan_i2c_core.o elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_I2C) += elan_i2c_i2c.o elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_SMBUS) += elan_i2c_smbus.o diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a84f8ed2ba5d..ab9bfe2af381 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1999,16 +1999,27 @@ static int __init psmouse_init(void) synaptics_module_init(); hgpk_module_init(); + err = psmouse_smbus_module_init(); + if (err) + return err; + kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0); if (!kpsmoused_wq) { pr_err("failed to create kpsmoused workqueue\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_smbus_exit; } err = serio_register_driver(&psmouse_drv); if (err) - destroy_workqueue(kpsmoused_wq); + goto err_destroy_wq; + return 0; + +err_destroy_wq: + destroy_workqueue(kpsmoused_wq); +err_smbus_exit: + psmouse_smbus_module_exit(); return err; } @@ -2016,6 +2027,7 @@ static void __exit psmouse_exit(void) { serio_unregister_driver(&psmouse_drv); destroy_workqueue(kpsmoused_wq); + psmouse_smbus_module_exit(); } module_init(psmouse_init); diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c new file mode 100644 index 000000000000..061c1cc44aef --- /dev/null +++ b/drivers/input/mouse/psmouse-smbus.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2017 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include "psmouse.h" + +struct psmouse_smbus_dev { + struct i2c_board_info board; + struct psmouse *psmouse; + struct i2c_client *client; + struct list_head node; + bool dead; +}; + +static LIST_HEAD(psmouse_smbus_list); +static DEFINE_MUTEX(psmouse_smbus_mutex); + +static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter) +{ + struct psmouse_smbus_dev *smbdev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY)) + return; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry(smbdev, &psmouse_smbus_list, node) { + if (smbdev->dead) + continue; + + if (smbdev->client) + continue; + + /* + * Here would be a good place to check if device is actually + * present, but it seems that SMBus will not respond unless we + * fully reset PS/2 connection. So cross our fingers, and try + * to switch over, hopefully our system will not have too many + * "host notify" I2C adapters. + */ + psmouse_dbg(smbdev->psmouse, + "SMBus candidate adapter appeared, triggering rescan\n"); + serio_rescan(smbdev->psmouse->ps2dev.serio); + } + + mutex_unlock(&psmouse_smbus_mutex); +} + +static void psmouse_smbus_detach_i2c_client(struct i2c_client *client) +{ + struct psmouse_smbus_dev *smbdev; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry(smbdev, &psmouse_smbus_list, node) { + if (smbdev->client == client) { + psmouse_dbg(smbdev->psmouse, + "Marking SMBus companion %s as gone\n", + dev_name(&smbdev->client->dev)); + smbdev->client = NULL; + smbdev->dead = true; + serio_rescan(smbdev->psmouse->ps2dev.serio); + } + } + + kfree(client->dev.platform_data); + client->dev.platform_data = NULL; + + mutex_unlock(&psmouse_smbus_mutex); +} + +static int psmouse_smbus_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->type == &i2c_adapter_type) + psmouse_smbus_check_adapter(to_i2c_adapter(dev)); + break; + + case BUS_NOTIFY_REMOVED_DEVICE: + if (dev->type != &i2c_adapter_type) + psmouse_smbus_detach_i2c_client(to_i2c_client(dev)); + break; + } + + return 0; +} + +static struct notifier_block psmouse_smbus_notifier = { + .notifier_call = psmouse_smbus_notifier_call, +}; + +static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse) +{ + return PSMOUSE_FULL_PACKET; +} + +static int psmouse_smbus_reconnect(struct psmouse *psmouse) +{ + psmouse_deactivate(psmouse); + + return 0; +} + +struct psmouse_smbus_removal_work { + struct work_struct work; + struct i2c_client *client; +}; + +static void psmouse_smbus_remove_i2c_device(struct work_struct *work) +{ + struct psmouse_smbus_removal_work *rwork = + container_of(work, struct psmouse_smbus_removal_work, work); + + dev_dbg(&rwork->client->dev, "destroying SMBus companion device\n"); + i2c_unregister_device(rwork->client); + + kfree(rwork); +} + +/* + * This schedules removal of SMBus companion device. We have to do + * it in a separate tread to avoid deadlocking on psmouse_mutex in + * case the device has a trackstick (which is also driven by psmouse). + * + * Note that this may be racing with i2c adapter removal, but we + * can't do anything about that: i2c automatically destroys clients + * attached to an adapter that is being removed. This has to be + * fixed in i2c core. + */ +static void psmouse_smbus_schedule_remove(struct i2c_client *client) +{ + struct psmouse_smbus_removal_work *rwork; + + rwork = kzalloc(sizeof(*rwork), GFP_KERNEL); + if (rwork) { + INIT_WORK(&rwork->work, psmouse_smbus_remove_i2c_device); + rwork->client = client; + + schedule_work(&rwork->work); + } +} + +static void psmouse_smbus_disconnect(struct psmouse *psmouse) +{ + struct psmouse_smbus_dev *smbdev = psmouse->private; + + mutex_lock(&psmouse_smbus_mutex); + list_del(&smbdev->node); + mutex_unlock(&psmouse_smbus_mutex); + + if (smbdev->client) { + psmouse_dbg(smbdev->psmouse, + "posting removal request for SMBus companion %s\n", + dev_name(&smbdev->client->dev)); + psmouse_smbus_schedule_remove(smbdev->client); + } + + kfree(smbdev); + psmouse->private = NULL; +} + +static int psmouse_smbus_create_companion(struct device *dev, void *data) +{ + struct psmouse_smbus_dev *smbdev = data; + unsigned short addr_list[] = { smbdev->board.addr, I2C_CLIENT_END }; + struct i2c_adapter *adapter; + + adapter = i2c_verify_adapter(dev); + if (!adapter) + return 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY)) + return 0; + + smbdev->client = i2c_new_probed_device(adapter, &smbdev->board, + addr_list, NULL); + if (!smbdev->client) + return 0; + + /* We have our(?) device, stop iterating i2c bus. */ + return 1; +} + +void psmouse_smbus_cleanup(struct psmouse *psmouse) +{ + struct psmouse_smbus_dev *smbdev, *tmp; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { + if (psmouse == smbdev->psmouse) { + list_del(&smbdev->node); + kfree(smbdev); + } + } + + mutex_unlock(&psmouse_smbus_mutex); +} + +int psmouse_smbus_init(struct psmouse *psmouse, + const struct i2c_board_info *board, + const void *pdata, size_t pdata_size, + bool leave_breadcrumbs) +{ + struct psmouse_smbus_dev *smbdev; + int error; + + smbdev = kzalloc(sizeof(*smbdev), GFP_KERNEL); + if (!smbdev) + return -ENOMEM; + + smbdev->psmouse = psmouse; + smbdev->board = *board; + + smbdev->board.platform_data = kmemdup(pdata, pdata_size, GFP_KERNEL); + if (!smbdev->board.platform_data) { + kfree(smbdev); + return -ENOMEM; + } + + psmouse->private = smbdev; + psmouse->protocol_handler = psmouse_smbus_process_byte; + psmouse->reconnect = psmouse_smbus_reconnect; + psmouse->fast_reconnect = psmouse_smbus_reconnect; + psmouse->disconnect = psmouse_smbus_disconnect; + psmouse->resync_time = 0; + + psmouse_deactivate(psmouse); + + mutex_lock(&psmouse_smbus_mutex); + list_add_tail(&smbdev->node, &psmouse_smbus_list); + mutex_unlock(&psmouse_smbus_mutex); + + /* Bind to already existing adapters right away */ + error = i2c_for_each_dev(smbdev, psmouse_smbus_create_companion); + + if (smbdev->client) { + /* We have our companion device */ + return 0; + } + + /* + * If we did not create i2c device we will not need platform + * data even if we are leaving breadcrumbs. + */ + kfree(smbdev->board.platform_data); + smbdev->board.platform_data = NULL; + + if (error < 0 || !leave_breadcrumbs) { + mutex_lock(&psmouse_smbus_mutex); + list_del(&smbdev->node); + mutex_unlock(&psmouse_smbus_mutex); + + kfree(smbdev); + } + + return error < 0 ? error : -EAGAIN; +} + +int __init psmouse_smbus_module_init(void) +{ + int error; + + error = bus_register_notifier(&i2c_bus_type, &psmouse_smbus_notifier); + if (error) { + pr_err("failed to register i2c bus notifier: %d\n", error); + return error; + } + + return 0; +} + +void psmouse_smbus_module_exit(void) +{ + bus_unregister_notifier(&i2c_bus_type, &psmouse_smbus_notifier); + flush_scheduled_work(); +} diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index e853dee05e79..05110832109c 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -209,5 +209,34 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ &(psmouse)->ps2dev.serio->dev, \ psmouse_fmt(format), ##__VA_ARGS__) +#ifdef CONFIG_MOUSE_PS2_SMBUS + +int psmouse_smbus_module_init(void); +void psmouse_smbus_module_exit(void); + +struct i2c_board_info; + +int psmouse_smbus_init(struct psmouse *psmouse, + const struct i2c_board_info *board, + const void *pdata, size_t pdata_size, + bool leave_breadcrumbs); +void psmouse_smbus_cleanup(struct psmouse *psmouse); + +#else /* !CONFIG_MOUSE_PS2_SMBUS */ + +static inline int psmouse_smbus_module_init(void) +{ + return 0; +} + +static inline void psmouse_smbus_module_exit(void) +{ +} + +static inline void psmouse_smbus_cleanup(struct psmouse *psmouse) +{ +} + +#endif /* CONFIG_MOUSE_PS2_SMBUS */ #endif /* _PSMOUSE_H */ -- cgit From 6c53694fb2223746738d1d0cea71456ca88c8fb2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Mar 2017 15:51:33 -0800 Subject: Input: synaptics - split device info into a separate structure In preparation for SMBus/Intertouch device support, move static device information that we query form the touchpad upon initialization into separate structure. This will allow us to query the device without allocating memory first. Also stop using "unsigned long", everything fits into 32 bit chunks. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 392 ++++++++++++++++++++++------------------ drivers/input/mouse/synaptics.h | 28 +-- 2 files changed, 233 insertions(+), 187 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 6a23c21968c1..0e08e2d497e9 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -127,9 +127,9 @@ static bool cr48_profile_sensor; struct min_max_quirk { const char * const *pnp_ids; struct { - unsigned long int min, max; + u32 min, max; } board_id; - int x_min, x_max, y_min, y_max; + u32 x_min, x_max, y_min, y_max; }; static const struct min_max_quirk min_max_pnpid_table[] = { @@ -248,27 +248,31 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned * Read the model-id bytes from the touchpad * see also SYN_MODEL_* macros */ -static int synaptics_model_id(struct psmouse *psmouse) +static int synaptics_model_id(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char mi[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi)) - return -1; - priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2]; + error = synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi); + if (error) + return error; + + info->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2]; return 0; } -static int synaptics_more_extended_queries(struct psmouse *psmouse) +static int synaptics_more_extended_queries(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char buf[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf)) - return -1; - - priv->ext_cap_10 = (buf[0]<<16) | (buf[1]<<8) | buf[2]; + error = synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf); + if (error) + return error; + info->ext_cap_10 = (buf[0] << 16) | (buf[1] << 8) | buf[2]; return 0; } @@ -276,21 +280,24 @@ static int synaptics_more_extended_queries(struct psmouse *psmouse) * Read the board id and the "More Extended Queries" from the touchpad * The board id is encoded in the "QUERY MODES" response */ -static int synaptics_query_modes(struct psmouse *psmouse) +static int synaptics_query_modes(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char bid[3]; + int error; /* firmwares prior 7.5 have no board_id encoded */ - if (SYN_ID_FULL(priv->identity) < 0x705) + if (SYN_ID_FULL(info->identity) < 0x705) return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid)) - return -1; - priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; + error = synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid); + if (error) + return error; + + info->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; if (SYN_MEXT_CAP_BIT(bid[0])) - return synaptics_more_extended_queries(psmouse); + return synaptics_more_extended_queries(psmouse, info); return 0; } @@ -298,14 +305,17 @@ static int synaptics_query_modes(struct psmouse *psmouse) /* * Read the firmware id from the touchpad */ -static int synaptics_firmware_id(struct psmouse *psmouse) +static int synaptics_firmware_id(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char fwid[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid)) - return -1; - priv->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; + error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); + if (error) + return error; + + info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; return 0; } @@ -313,53 +323,57 @@ static int synaptics_firmware_id(struct psmouse *psmouse) * Read the capability-bits from the touchpad * see also the SYN_CAP_* macros */ -static int synaptics_capability(struct psmouse *psmouse) +static int synaptics_capability(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char cap[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) - return -1; - priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - priv->ext_cap = priv->ext_cap_0c = 0; + error = synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap); + if (error) + return error; + + info->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; + info->ext_cap = info->ext_cap_0c = 0; /* * Older firmwares had submodel ID fixed to 0x47 */ - if (SYN_ID_FULL(priv->identity) < 0x705 && - SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) { - return -1; + if (SYN_ID_FULL(info->identity) < 0x705 && + SYN_CAP_SUBMODEL_ID(info->capabilities) != 0x47) { + return -ENXIO; } /* * Unless capExtended is set the rest of the flags should be ignored */ - if (!SYN_CAP_EXTENDED(priv->capabilities)) - priv->capabilities = 0; + if (!SYN_CAP_EXTENDED(info->capabilities)) + info->capabilities = 0; - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 1) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { psmouse_warn(psmouse, "device claims to have extended capabilities, but I'm not able to read them.\n"); } else { - priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; + info->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; /* * if nExtBtn is greater than 8 it should be considered * invalid and treated as 0 */ - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8) - priv->ext_cap &= 0xff0fff; + if (SYN_CAP_MULTI_BUTTON_NO(info->ext_cap) > 8) + info->ext_cap &= 0xff0fff; } } - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 4) { + error = synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap); + if (error) psmouse_warn(psmouse, "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); - } else { - priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - } + else + info->ext_cap_0c = + (cap[0] << 16) | (cap[1] << 8) | cap[2]; } return 0; @@ -369,17 +383,18 @@ static int synaptics_capability(struct psmouse *psmouse) * Identify Touchpad * See also the SYN_ID_* macros */ -static int synaptics_identify(struct psmouse *psmouse) +static int synaptics_identify(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char id[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id)) - return -1; - priv->identity = (id[0]<<16) | (id[1]<<8) | id[2]; - if (SYN_ID_IS_SYNAPTICS(priv->identity)) - return 0; - return -1; + error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); + if (error) + return error; + + info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; + return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; } /* @@ -387,52 +402,58 @@ static int synaptics_identify(struct psmouse *psmouse) * Resolution is left zero if touchpad does not support the query */ -static int synaptics_resolution(struct psmouse *psmouse) +static int synaptics_resolution(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char resp[3]; + int error; - if (SYN_ID_MAJOR(priv->identity) < 4) + if (SYN_ID_MAJOR(info->identity) < 4) return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) { + error = synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp); + if (!error) { if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) { - priv->x_res = resp[0]; /* x resolution in units/mm */ - priv->y_res = resp[2]; /* y resolution in units/mm */ + info->x_res = resp[0]; /* x resolution in units/mm */ + info->y_res = resp[2]; /* y resolution in units/mm */ } } - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && - SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 5 && + SYN_CAP_MAX_DIMENSIONS(info->ext_cap_0c)) { + error = synaptics_send_cmd(psmouse, + SYN_QUE_EXT_MAX_COORDS, resp); + if (error) { psmouse_warn(psmouse, "device claims to have max coordinates query, but I'm not able to read it.\n"); } else { - priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); + info->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); + info->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); psmouse_info(psmouse, "queried max coordinates: x [..%d], y [..%d]\n", - priv->x_max, priv->y_max); + info->x_max, info->y_max); } } - if (SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c) && - (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 || + if (SYN_CAP_MIN_DIMENSIONS(info->ext_cap_0c) && + (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 7 || /* * Firmware v8.1 does not report proper number of extended * capabilities, but has been proven to report correct min * coordinates. */ - SYN_ID_FULL(priv->identity) == 0x801)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) { + SYN_ID_FULL(info->identity) == 0x801)) { + error = synaptics_send_cmd(psmouse, + SYN_QUE_EXT_MIN_COORDS, resp); + if (error) { psmouse_warn(psmouse, "device claims to have min coordinates query, but I'm not able to read it.\n"); } else { - priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); + info->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); + info->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); psmouse_info(psmouse, "queried min coordinates: x [%d..], y [%d..]\n", - priv->x_min, priv->y_min); + info->x_min, info->y_min); } } @@ -443,9 +464,9 @@ static int synaptics_resolution(struct psmouse *psmouse) * Apply quirk(s) if the hardware matches */ -static void synaptics_apply_quirks(struct psmouse *psmouse) +static void synaptics_apply_quirks(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; int i; for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { @@ -454,41 +475,53 @@ static void synaptics_apply_quirks(struct psmouse *psmouse) continue; if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID && - priv->board_id < min_max_pnpid_table[i].board_id.min) + info->board_id < min_max_pnpid_table[i].board_id.min) continue; if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID && - priv->board_id > min_max_pnpid_table[i].board_id.max) + info->board_id > min_max_pnpid_table[i].board_id.max) continue; - priv->x_min = min_max_pnpid_table[i].x_min; - priv->x_max = min_max_pnpid_table[i].x_max; - priv->y_min = min_max_pnpid_table[i].y_min; - priv->y_max = min_max_pnpid_table[i].y_max; + info->x_min = min_max_pnpid_table[i].x_min; + info->x_max = min_max_pnpid_table[i].x_max; + info->y_min = min_max_pnpid_table[i].y_min; + info->y_max = min_max_pnpid_table[i].y_max; psmouse_info(psmouse, "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n", - priv->x_min, priv->x_max, - priv->y_min, priv->y_max); + info->x_min, info->x_max, + info->y_min, info->y_max); break; } } -static int synaptics_query_hardware(struct psmouse *psmouse) +static int synaptics_query_hardware(struct psmouse *psmouse, + struct synaptics_device_info *info) { - if (synaptics_identify(psmouse)) - return -1; - if (synaptics_model_id(psmouse)) - return -1; - if (synaptics_firmware_id(psmouse)) - return -1; - if (synaptics_query_modes(psmouse)) - return -1; - if (synaptics_capability(psmouse)) - return -1; - if (synaptics_resolution(psmouse)) - return -1; + int error; + + error = synaptics_identify(psmouse, info); + if (error) + return error; + + error = synaptics_model_id(psmouse, info); + if (error) + return error; + + error = synaptics_firmware_id(psmouse, info); + if (error) + return error; - synaptics_apply_quirks(psmouse); + error = synaptics_query_modes(psmouse, info); + if (error) + return error; + + error = synaptics_capability(psmouse, info); + if (error) + return error; + + error = synaptics_resolution(psmouse, info); + if (error) + return error; return 0; } @@ -498,8 +531,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static unsigned char param = 0xc8; struct synaptics_data *priv = psmouse->private; - if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))) + if (!(SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c))) return 0; if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) @@ -509,7 +542,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) return -1; /* Advanced gesture mode also sends multi finger data */ - priv->capabilities |= BIT(1); + priv->info.capabilities |= BIT(1); return 0; } @@ -525,7 +558,7 @@ static int synaptics_set_mode(struct psmouse *psmouse) priv->mode |= SYN_BIT_DISABLE_GESTURE; if (psmouse->rate >= 80) priv->mode |= SYN_BIT_HIGH_RATE; - if (SYN_CAP_EXTENDED(priv->capabilities)) + if (SYN_CAP_EXTENDED(priv->info.capabilities)) priv->mode |= SYN_BIT_W_MODE; if (synaptics_mode_cmd(psmouse, priv->mode)) @@ -693,7 +726,7 @@ static void synaptics_parse_ext_buttons(const unsigned char buf[], struct synaptics_hw_state *hw) { unsigned int ext_bits = - (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; + (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1; unsigned int ext_mask = GENMASK(ext_bits - 1, 0); hw->ext_buttons = buf[4] & ext_mask; @@ -706,13 +739,13 @@ static int synaptics_parse_hw_state(const unsigned char buf[], { memset(hw, 0, sizeof(struct synaptics_hw_state)); - if (SYN_MODEL_NEWABS(priv->model_id)) { + if (SYN_MODEL_NEWABS(priv->info.model_id)) { hw->w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); - if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && + if ((SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c)) && hw->w == 2) { synaptics_parse_agm(buf, priv, hw); return 1; @@ -765,7 +798,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], hw->left = priv->report_press; - } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + } else if (SYN_CAP_CLICKPAD(priv->info.ext_cap_0c)) { /* * Clickpad's button is transmitted as middle button, * however, since it is primary button, we will report @@ -773,18 +806,18 @@ static int synaptics_parse_hw_state(const unsigned char buf[], */ hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; - } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { + } else if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; if (hw->w == 2) hw->scroll = (signed char)(buf[1]); } - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 && + if (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) > 0 && ((buf[0] ^ buf[3]) & 0x02)) { synaptics_parse_ext_buttons(buf, priv, hw); } @@ -853,19 +886,19 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; - int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; + int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1; int i; - if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) + if (!SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap)) return; /* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */ - if ((SYN_ID_FULL(priv->identity) == 0x801 || - SYN_ID_FULL(priv->identity) == 0x802) && + if ((SYN_ID_FULL(priv->info.identity) == 0x801 || + SYN_ID_FULL(priv->info.identity) == 0x802) && !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02)) return; - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) { + if (!SYN_CAP_EXT_BUTTONS_STICK(priv->info.ext_cap_10)) { for (i = 0; i < ext_bits; i++) { input_report_key(dev, BTN_0 + 2 * i, hw->ext_buttons & (1 << i)); @@ -903,10 +936,10 @@ static void synaptics_report_buttons(struct psmouse *psmouse, input_report_key(dev, BTN_LEFT, hw->left); input_report_key(dev, BTN_RIGHT, hw->right); - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) input_report_key(dev, BTN_MIDDLE, hw->middle); - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { input_report_key(dev, BTN_FORWARD, hw->up); input_report_key(dev, BTN_BACK, hw->down); } @@ -931,7 +964,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, pos[i].y = synaptics_invert_y(hw[i]->y); } - input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res); + input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->info.x_res); for (i = 0; i < nsemi; i++) { input_mt_slot(dev, slot[i]); @@ -985,6 +1018,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; + struct synaptics_device_info *info = &priv->info; struct synaptics_hw_state hw; int num_fingers; int finger_width; @@ -992,7 +1026,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) return; - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { + if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) { synaptics_image_sensor_process(psmouse, &hw); return; } @@ -1020,18 +1054,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (hw.z > 0 && hw.x > 1) { num_fingers = 1; finger_width = 5; - if (SYN_CAP_EXTENDED(priv->capabilities)) { + if (SYN_CAP_EXTENDED(info->capabilities)) { switch (hw.w) { case 0 ... 1: - if (SYN_CAP_MULTIFINGER(priv->capabilities)) + if (SYN_CAP_MULTIFINGER(info->capabilities)) num_fingers = hw.w + 2; break; case 2: - if (SYN_MODEL_PEN(priv->model_id)) + if (SYN_MODEL_PEN(info->model_id)) ; /* Nothing, treat a pen as a single finger */ break; case 4 ... 15: - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) finger_width = hw.w; break; } @@ -1046,7 +1080,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) return; } - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) + if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) synaptics_report_semi_mt_data(dev, &hw, &priv->agm, num_fingers); @@ -1063,11 +1097,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) } input_report_abs(dev, ABS_PRESSURE, hw.z); - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(info->capabilities)) { input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); } @@ -1129,7 +1163,7 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (SYN_CAP_PASS_THROUGH(priv->capabilities) && + if (SYN_CAP_PASS_THROUGH(priv->info.capabilities) && synaptics_is_pt_packet(psmouse->packet)) { if (priv->pt_port) synaptics_pass_pt_packet(priv->pt_port, @@ -1148,26 +1182,27 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) * Driver initialization/cleanup functions ****************************************************************************/ static void set_abs_position_params(struct input_dev *dev, - struct synaptics_data *priv, int x_code, - int y_code) + struct synaptics_device_info *info, + int x_code, int y_code) { - int x_min = priv->x_min ?: XMIN_NOMINAL; - int x_max = priv->x_max ?: XMAX_NOMINAL; - int y_min = priv->y_min ?: YMIN_NOMINAL; - int y_max = priv->y_max ?: YMAX_NOMINAL; - int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? + int x_min = info->x_min ?: XMIN_NOMINAL; + int x_max = info->x_max ?: XMAX_NOMINAL; + int y_min = info->y_min ?: YMIN_NOMINAL; + int y_max = info->y_max ?: YMAX_NOMINAL; + int fuzz = SYN_CAP_REDUCED_FILTERING(info->ext_cap_0c) ? SYN_REDUCED_FILTER_FUZZ : 0; input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0); input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0); - input_abs_set_res(dev, x_code, priv->x_res); - input_abs_set_res(dev, y_code, priv->y_res); + input_abs_set_res(dev, x_code, info->x_res); + input_abs_set_res(dev, y_code, info->y_res); } static void set_input_params(struct psmouse *psmouse, struct synaptics_data *priv) { struct input_dev *dev = psmouse->dev; + struct synaptics_device_info *info = &priv->info; int i; /* Things that apply to both modes */ @@ -1176,7 +1211,7 @@ static void set_input_params(struct psmouse *psmouse, __set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(info->capabilities)) __set_bit(BTN_MIDDLE, dev->keybit); if (!priv->absolute_mode) { @@ -1189,15 +1224,15 @@ static void set_input_params(struct psmouse *psmouse, /* Absolute mode */ __set_bit(EV_ABS, dev->evbit); - set_abs_position_params(dev, priv, ABS_X, ABS_Y); + set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); if (cr48_profile_sensor) input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); + if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) { + set_abs_position_params(dev, info, + ABS_MT_POSITION_X, ABS_MT_POSITION_Y); /* Image sensors can report per-contact pressure */ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); @@ -1205,9 +1240,9 @@ static void set_input_params(struct psmouse *psmouse, /* Image sensors can signal 4 and 5 finger clicks */ __set_bit(BTN_TOOL_QUADTAP, dev->keybit); __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); - } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); + } else if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) { + set_abs_position_params(dev, info, + ABS_MT_POSITION_X, ABS_MT_POSITION_Y); /* * Profile sensor in CR-48 tracks contacts reasonably well, * other non-image sensors with AGM use semi-mt. @@ -1218,35 +1253,35 @@ static void set_input_params(struct psmouse *psmouse, INPUT_MT_TRACK : INPUT_MT_SEMI_MT)); } - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); __set_bit(BTN_TOUCH, dev->keybit); __set_bit(BTN_TOOL_FINGER, dev->keybit); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(info->capabilities)) { __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); } - if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || - SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(info->capabilities) || + SYN_CAP_MIDDLE_BUTTON(info->capabilities)) { __set_bit(BTN_FORWARD, dev->keybit); __set_bit(BTN_BACK, dev->keybit); } - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) - for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) + if (!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10)) + for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(info->ext_cap); i++) __set_bit(BTN_0 + i, dev->keybit); __clear_bit(EV_REL, dev->evbit); __clear_bit(REL_X, dev->relbit); __clear_bit(REL_Y, dev->relbit); - if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + if (SYN_CAP_CLICKPAD(info->ext_cap_0c)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && - !SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) + !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10)) __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); /* Clickpads report only left button */ __clear_bit(BTN_RIGHT, dev->keybit); @@ -1300,7 +1335,8 @@ static void synaptics_disconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) + if (!priv->absolute_mode && + SYN_ID_DISGEST_SUPPORTED(priv->info.identity)) device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_disable_gesture.dattr); @@ -1312,7 +1348,7 @@ static void synaptics_disconnect(struct psmouse *psmouse) static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - struct synaptics_data old_priv = *priv; + struct synaptics_device_info info; unsigned char param[2]; int retry = 0; int error; @@ -1339,7 +1375,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) if (retry > 1) psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); - if (synaptics_query_hardware(psmouse)) { + if (synaptics_query_hardware(psmouse, &info)) { psmouse_err(psmouse, "Unable to query device.\n"); return -1; } @@ -1349,16 +1385,16 @@ static int synaptics_reconnect(struct psmouse *psmouse) return -1; } - if (old_priv.identity != priv->identity || - old_priv.model_id != priv->model_id || - old_priv.capabilities != priv->capabilities || - old_priv.ext_cap != priv->ext_cap) { + if (info.identity != priv->info.identity || + info.model_id != priv->info.model_id || + info.capabilities != priv->info.capabilities || + info.ext_cap != priv->info.ext_cap) { psmouse_err(psmouse, - "hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", - old_priv.identity, priv->identity, - old_priv.model_id, priv->model_id, - old_priv.capabilities, priv->capabilities, - old_priv.ext_cap, priv->ext_cap); + "hardware appears to be different: id(%u-%u), model(%u-%u), caps(%x-%x), ext(%x-%x).\n", + priv->info.identity, info.identity, + priv->info.model_id, info.model_id, + priv->info.capabilities, info.capabilities, + priv->info.ext_cap, info.ext_cap); return -1; } @@ -1442,6 +1478,7 @@ void __init synaptics_module_init(void) static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) { struct synaptics_data *priv; + struct synaptics_device_info *info; int err = -1; /* @@ -1460,15 +1497,19 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) if (!priv) return -ENOMEM; + info = &priv->info; + psmouse_reset(psmouse); - if (synaptics_query_hardware(psmouse)) { + if (synaptics_query_hardware(psmouse, info)) { psmouse_err(psmouse, "Unable to query device.\n"); goto init_fail; } + synaptics_apply_quirks(psmouse, info); + priv->absolute_mode = absolute_mode; - if (SYN_ID_DISGEST_SUPPORTED(priv->identity)) + if (SYN_ID_DISGEST_SUPPORTED(info->identity)) priv->disable_gesture = true; /* @@ -1482,15 +1523,16 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) goto init_fail; } - priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; + priv->pkt_type = SYN_MODEL_NEWABS(info->model_id) ? + SYN_NEWABS : SYN_OLDABS; psmouse_info(psmouse, - "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n", - SYN_ID_MODEL(priv->identity), - SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), - priv->model_id, - priv->capabilities, priv->ext_cap, priv->ext_cap_0c, - priv->ext_cap_10, priv->board_id, priv->firmware_id); + "Touchpad model: %u, fw: %u.%u, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n", + SYN_ID_MODEL(info->identity), + SYN_ID_MAJOR(info->identity), SYN_ID_MINOR(info->identity), + info->model_id, + info->capabilities, info->ext_cap, info->ext_cap_0c, + info->ext_cap_10, info->board_id, info->firmware_id); set_input_params(psmouse, priv); @@ -1501,8 +1543,8 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) * Hardware info bits seem to be good candidates as they * are documented to be for Synaptics corp. internal use. */ - psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) | - (priv->model_id & 0x000000ff); + psmouse->model = ((info->model_id & 0x00ff0000) >> 8) | + (info->model_id & 0x000000ff); if (absolute_mode) { psmouse->protocol_handler = synaptics_process_byte; @@ -1520,7 +1562,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) /* Synaptics can usually stay in sync without extra help */ psmouse->resync_time = 0; - if (SYN_CAP_PASS_THROUGH(priv->capabilities)) + if (SYN_CAP_PASS_THROUGH(info->capabilities)) synaptics_pt_create(psmouse); /* @@ -1535,7 +1577,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) psmouse->rate = 40; } - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) { + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(info->identity)) { err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_disable_gesture.dattr); if (err) { diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index b76bb7a38472..d9b824fbddc2 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -161,19 +161,23 @@ struct synaptics_hw_state { signed char scroll; }; +/* Data read from the touchpad */ +struct synaptics_device_info { + u32 model_id; /* Model-ID */ + u32 firmware_id; /* Firmware-ID */ + u32 board_id; /* Board-ID */ + u32 capabilities; /* Capabilities */ + u32 ext_cap; /* Extended Capabilities */ + u32 ext_cap_0c; /* Ext Caps from 0x0c query */ + u32 ext_cap_10; /* Ext Caps from 0x10 query */ + u32 identity; /* Identification */ + u32 x_res, y_res; /* X/Y resolution in units/mm */ + u32 x_max, y_max; /* Max coordinates (from FW) */ + u32 x_min, y_min; /* Min coordinates (from FW) */ +}; + struct synaptics_data { - /* Data read from the touchpad */ - unsigned long int model_id; /* Model-ID */ - unsigned long int firmware_id; /* Firmware-ID */ - unsigned long int board_id; /* Board-ID */ - unsigned long int capabilities; /* Capabilities */ - unsigned long int ext_cap; /* Extended Capabilities */ - unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ - unsigned long int ext_cap_10; /* Ext Caps from 0x10 query */ - unsigned long int identity; /* Identification */ - unsigned int x_res, y_res; /* X/Y resolution in units/mm */ - unsigned int x_max, y_max; /* Max coordinates (from FW) */ - unsigned int x_min, y_min; /* Min coordinates (from FW) */ + struct synaptics_device_info info; unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ -- cgit From e839ffab028981ac77f650faf8c84f16e1719738 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Mar 2017 14:13:53 -0800 Subject: Input: synaptics - add support for Intertouch devices Most of the Synaptics devices are connected through PS/2 and a different bus (SMBus or HID over I2C). The secondary bus capability is indicated by the InterTouch bit in extended capability 0x0C. We only enable the InterTouch device to be created for the laptops registered with the top software button property or those we know that are functional. In the future, we might change the default to always rely on the InterTouch bus. Currently, users can enable/disable the feature with the psmouse parameter synaptics_intertouch. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 12 + drivers/input/mouse/psmouse-base.c | 24 +- drivers/input/mouse/psmouse.h | 1 + drivers/input/mouse/synaptics.c | 554 +++++++++++++++++++++++++------------ drivers/input/mouse/synaptics.h | 5 +- 5 files changed, 421 insertions(+), 175 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 87bde8a210c7..89ebb8f39fee 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -78,6 +78,18 @@ config MOUSE_PS2_SYNAPTICS If unsure, say Y. +config MOUSE_PS2_SYNAPTICS_SMBUS + bool "Synaptics PS/2 SMbus companion" if EXPERT + default y + depends on MOUSE_PS2 + depends on I2C=y || I2C=MOUSE_PS2 + select MOUSE_PS2_SMBUS + help + Say Y here if you have a Synaptics RMI4 touchpad connected to + to an SMBus, but enumerated through PS/2. + + If unsure, say Y. + config MOUSE_PS2_CYPRESS bool "Cypress PS/2 mouse protocol extension" if EXPERT default y diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index ab9bfe2af381..f73b47b8c578 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -773,7 +773,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "SynPS/2", .alias = "synaptics", .detect = synaptics_detect, - .init = synaptics_init, + .init = synaptics_init_absolute, }, { .type = PSMOUSE_SYNAPTICS_RELATIVE, @@ -783,6 +783,16 @@ static const struct psmouse_protocol psmouse_protocols[] = { .init = synaptics_init_relative, }, #endif +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS + { + .type = PSMOUSE_SYNAPTICS_SMBUS, + .name = "SynSMBus", + .alias = "synaptics-smbus", + .detect = synaptics_detect, + .init = synaptics_init_smbus, + .smbus_companion = true, + }, +#endif #ifdef CONFIG_MOUSE_PS2_ALPS { .type = PSMOUSE_ALPS, @@ -1011,6 +1021,7 @@ static int psmouse_extensions(struct psmouse *psmouse, unsigned int max_proto, bool set_properties) { bool synaptics_hardware = false; + int ret; /* * Always check for focaltech, this is safe as it uses pnp-id @@ -1073,9 +1084,14 @@ static int psmouse_extensions(struct psmouse *psmouse, * enabled first, since we try detecting Synaptics * even when protocol is disabled. */ - if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) && - (!set_properties || synaptics_init(psmouse) == 0)) { - return PSMOUSE_SYNAPTICS; + if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) || + IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)) { + if (!set_properties) + return PSMOUSE_SYNAPTICS; + + ret = synaptics_init(psmouse); + if (ret >= 0) + return ret; } /* diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 05110832109c..38855e425f01 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -66,6 +66,7 @@ enum psmouse_type { PSMOUSE_FOCALTECH, PSMOUSE_VMMOUSE, PSMOUSE_BYD, + PSMOUSE_SYNAPTICS_SMBUS, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 0e08e2d497e9..d494c6c6aadc 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include "psmouse.h" #include "synaptics.h" @@ -119,59 +121,8 @@ void synaptics_reset(struct psmouse *psmouse) synaptics_mode_cmd(psmouse, 0); } -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS - -static bool cr48_profile_sensor; - -#define ANY_BOARD_ID 0 -struct min_max_quirk { - const char * const *pnp_ids; - struct { - u32 min, max; - } board_id; - u32 x_min, x_max, y_min, y_max; -}; - -static const struct min_max_quirk min_max_pnpid_table[] = { - { - (const char * const []){"LEN0033", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5052, 2258, 4832 - }, - { - (const char * const []){"LEN0042", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1232, 5710, 1156, 4696 - }, - { - (const char * const []){"LEN0034", "LEN0036", "LEN0037", - "LEN0039", "LEN2002", "LEN2004", - NULL}, - {ANY_BOARD_ID, 2961}, - 1024, 5112, 2024, 4832 - }, - { - (const char * const []){"LEN2000", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5113, 2021, 4832 - }, - { - (const char * const []){"LEN2001", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5022, 2508, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {2691, 2691}, - 1024, 5045, 2457, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1264, 5675, 1171, 4688 - }, - { } -}; +#if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \ + defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS) /* This list has been kindly provided by Synaptics. */ static const char * const topbuttonpad_pnp_ids[] = { @@ -211,37 +162,50 @@ static const char * const topbuttonpad_pnp_ids[] = { NULL }; -/* This list has been kindly provided by Synaptics. */ -static const char * const forcepad_pnp_ids[] = { - "SYN300D", - "SYN3014", +static const char * const smbus_pnp_ids[] = { + /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ + "LEN0048", /* X1 Carbon 3 */ + "LEN0046", /* X250 */ + "LEN004a", /* W541 */ + "LEN200f", /* T450s */ NULL }; -/***************************************************************************** - * Synaptics communications functions - ****************************************************************************/ - /* - * Synaptics touchpads report the y coordinate from bottom to top, which is - * opposite from what userspace expects. - * This function is used to invert y before reporting. + * Send a command to the synpatics touchpad by special commands */ -static int synaptics_invert_y(int y) +static int synaptics_send_cmd(struct psmouse *psmouse, + unsigned char c, unsigned char *param) { - return YMAX_NOMINAL + YMIN_NOMINAL - y; + int error; + + error = psmouse_sliced_command(psmouse, c); + if (error) + return error; + + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO); + if (error) + return error; + + return 0; } /* - * Send a command to the synpatics touchpad by special commands + * Identify Touchpad + * See also the SYN_ID_* macros */ -static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) +static int synaptics_identify(struct psmouse *psmouse, + struct synaptics_device_info *info) { - if (psmouse_sliced_command(psmouse, c)) - return -1; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; - return 0; + unsigned char id[3]; + int error; + + error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); + if (error) + return error; + + info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; + return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; } /* @@ -262,6 +226,23 @@ static int synaptics_model_id(struct psmouse *psmouse, return 0; } +/* + * Read the firmware id from the touchpad + */ +static int synaptics_firmware_id(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + unsigned char fwid[3]; + int error; + + error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); + if (error) + return error; + + info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; + return 0; +} + static int synaptics_more_extended_queries(struct psmouse *psmouse, struct synaptics_device_info *info) { @@ -302,23 +283,6 @@ static int synaptics_query_modes(struct psmouse *psmouse, return 0; } -/* - * Read the firmware id from the touchpad - */ -static int synaptics_firmware_id(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - unsigned char fwid[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); - if (error) - return error; - - info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; - return 0; -} - /* * Read the capability-bits from the touchpad * see also the SYN_CAP_* macros @@ -379,29 +343,10 @@ static int synaptics_capability(struct psmouse *psmouse, return 0; } -/* - * Identify Touchpad - * See also the SYN_ID_* macros - */ -static int synaptics_identify(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - unsigned char id[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); - if (error) - return error; - - info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; - return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; -} - /* * Read touchpad resolution and maximum reported coordinates * Resolution is left zero if touchpad does not support the query */ - static int synaptics_resolution(struct psmouse *psmouse, struct synaptics_device_info *info) { @@ -460,10 +405,118 @@ static int synaptics_resolution(struct psmouse *psmouse, return 0; } +static int synaptics_query_hardware(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + int error; + + error = synaptics_identify(psmouse, info); + if (error) + return error; + + error = synaptics_model_id(psmouse, info); + if (error) + return error; + + error = synaptics_firmware_id(psmouse, info); + if (error) + return error; + + error = synaptics_query_modes(psmouse, info); + if (error) + return error; + + error = synaptics_capability(psmouse, info); + if (error) + return error; + + error = synaptics_resolution(psmouse, info); + if (error) + return error; + + return 0; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS + +static bool cr48_profile_sensor; + +#define ANY_BOARD_ID 0 +struct min_max_quirk { + const char * const *pnp_ids; + struct { + u32 min, max; + } board_id; + u32 x_min, x_max, y_min, y_max; +}; + +static const struct min_max_quirk min_max_pnpid_table[] = { + { + (const char * const []){"LEN0033", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5052, 2258, 4832 + }, + { + (const char * const []){"LEN0042", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1232, 5710, 1156, 4696 + }, + { + (const char * const []){"LEN0034", "LEN0036", "LEN0037", + "LEN0039", "LEN2002", "LEN2004", + NULL}, + {ANY_BOARD_ID, 2961}, + 1024, 5112, 2024, 4832 + }, + { + (const char * const []){"LEN2000", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5113, 2021, 4832 + }, + { + (const char * const []){"LEN2001", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5022, 2508, 4832 + }, + { + (const char * const []){"LEN2006", NULL}, + {2691, 2691}, + 1024, 5045, 2457, 4832 + }, + { + (const char * const []){"LEN2006", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1264, 5675, 1171, 4688 + }, + { } +}; + +/* This list has been kindly provided by Synaptics. */ +static const char * const forcepad_pnp_ids[] = { + "SYN300D", + "SYN3014", + NULL +}; + +/***************************************************************************** + * Synaptics communications functions + ****************************************************************************/ + +/* + * Synaptics touchpads report the y coordinate from bottom to top, which is + * opposite from what userspace expects. + * This function is used to invert y before reporting. + */ +static int synaptics_invert_y(int y) +{ + return YMAX_NOMINAL + YMIN_NOMINAL - y; +} + /* * Apply quirk(s) if the hardware matches */ - static void synaptics_apply_quirks(struct psmouse *psmouse, struct synaptics_device_info *info) { @@ -494,38 +547,6 @@ static void synaptics_apply_quirks(struct psmouse *psmouse, } } -static int synaptics_query_hardware(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - int error; - - error = synaptics_identify(psmouse, info); - if (error) - return error; - - error = synaptics_model_id(psmouse, info); - if (error) - return error; - - error = synaptics_firmware_id(psmouse, info); - if (error) - return error; - - error = synaptics_query_modes(psmouse, info); - if (error) - return error; - - error = synaptics_capability(psmouse, info); - if (error) - return error; - - error = synaptics_resolution(psmouse, info); - if (error) - return error; - - return 0; -} - static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) { static unsigned char param = 0xc8; @@ -1335,6 +1356,12 @@ static void synaptics_disconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; + /* + * We might have left a breadcrumb when trying to + * set up SMbus companion. + */ + psmouse_smbus_cleanup(psmouse); + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->info.identity)) device_remove_file(&psmouse->ps2dev.serio->dev, @@ -1475,39 +1502,20 @@ void __init synaptics_module_init(void) cr48_profile_sensor = dmi_check_system(cr48_dmi_table); } -static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) +static int synaptics_init_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool absolute_mode) { struct synaptics_data *priv; - struct synaptics_device_info *info; - int err = -1; + int err; - /* - * The OLPC XO has issues with Synaptics' absolute mode; the constant - * packet spew overloads the EC such that key presses on the keyboard - * are missed. Given that, don't even attempt to use Absolute mode. - * Relative mode seems to work just fine. - */ - if (absolute_mode && broken_olpc_ec) { - psmouse_info(psmouse, - "OLPC XO detected, not enabling Synaptics protocol.\n"); - return -ENODEV; - } + synaptics_apply_quirks(psmouse, info); psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); if (!priv) return -ENOMEM; - info = &priv->info; - - psmouse_reset(psmouse); - - if (synaptics_query_hardware(psmouse, info)) { - psmouse_err(psmouse, "Unable to query device.\n"); - goto init_fail; - } - - synaptics_apply_quirks(psmouse, info); - + priv->info = *info; priv->absolute_mode = absolute_mode; if (SYN_ID_DISGEST_SUPPORTED(info->identity)) priv->disable_gesture = true; @@ -1518,7 +1526,8 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) */ priv->is_forcepad = psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids); - if (synaptics_set_mode(psmouse)) { + err = synaptics_set_mode(psmouse); + if (err) { psmouse_err(psmouse, "Unable to initialize device.\n"); goto init_fail; } @@ -1595,7 +1604,23 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) return err; } -int synaptics_init(struct psmouse *psmouse) +static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) +{ + struct synaptics_device_info info; + int error; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + return synaptics_init_ps2(psmouse, &info, absolute_mode); +} + +int synaptics_init_absolute(struct psmouse *psmouse) { return __synaptics_init(psmouse, true); } @@ -1605,15 +1630,204 @@ int synaptics_init_relative(struct psmouse *psmouse) return __synaptics_init(psmouse, false); } +static int synaptics_setup_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + bool absolute_mode = true; + int error; + + /* + * The OLPC XO has issues with Synaptics' absolute mode; the constant + * packet spew overloads the EC such that key presses on the keyboard + * are missed. Given that, don't even attempt to use Absolute mode. + * Relative mode seems to work just fine. + */ + if (broken_olpc_ec) { + psmouse_info(psmouse, + "OLPC XO detected, forcing relative protocol.\n"); + absolute_mode = false; + } + + error = synaptics_init_ps2(psmouse, info, absolute_mode); + if (error) + return error; + + return absolute_mode ? PSMOUSE_SYNAPTICS : PSMOUSE_SYNAPTICS_RELATIVE; +} + #else /* CONFIG_MOUSE_PS2_SYNAPTICS */ void __init synaptics_module_init(void) { } -int synaptics_init(struct psmouse *psmouse) +static int __maybe_unused +synaptics_setup_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info) { return -ENOSYS; } #endif /* CONFIG_MOUSE_PS2_SYNAPTICS */ + +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS + +/* + * The newest Synaptics device can use a secondary bus (called InterTouch) which + * provides a better bandwidth and allow a better control of the touchpads. + * This is used to decide if we need to use this bus or not. + */ +enum { + SYNAPTICS_INTERTOUCH_NOT_SET = -1, + SYNAPTICS_INTERTOUCH_OFF, + SYNAPTICS_INTERTOUCH_ON, +}; + +static int synaptics_intertouch = SYNAPTICS_INTERTOUCH_NOT_SET; +module_param_named(synaptics_intertouch, synaptics_intertouch, int, 0644); +MODULE_PARM_DESC(synaptics_intertouch, "Use a secondary bus for the Synaptics device."); + +static int synaptics_create_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + bool topbuttonpad = + psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && + !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10); + const struct rmi_device_platform_data pdata = { + .sensor_pdata = { + .sensor_type = rmi_sensor_touchpad, + .axis_align.flip_y = true, + /* to prevent cursors jumps: */ + .kernel_tracking = true, + .topbuttonpad = topbuttonpad, + }, + .f30_data = { + .buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c), + .trackstick_buttons = + !!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10), + }, + }; + const struct i2c_board_info intertouch_board = { + I2C_BOARD_INFO("rmi4_smbus", 0x2c), + .flags = I2C_CLIENT_HOST_NOTIFY, + }; + + return psmouse_smbus_init(psmouse, &intertouch_board, + &pdata, sizeof(pdata), + leave_breadcrumbs); +} + +/** + * synaptics_setup_intertouch - called once the PS/2 devices are enumerated + * and decides to instantiate a SMBus InterTouch device. + */ +static int synaptics_setup_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + int error; + + if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_OFF) + return -ENXIO; + + if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_NOT_SET) { + if (!psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && + !psmouse_matches_pnp_id(psmouse, smbus_pnp_ids)) + return -ENXIO; + } + + psmouse_info(psmouse, "Trying to set up SMBus access\n"); + + error = synaptics_create_intertouch(psmouse, info, leave_breadcrumbs); + if (error) { + if (error == -EAGAIN) + psmouse_info(psmouse, "SMbus companion is not ready yet\n"); + else + psmouse_err(psmouse, "unable to create intertouch device\n"); + + return error; + } + + return 0; +} + +int synaptics_init_smbus(struct psmouse *psmouse) +{ + struct synaptics_device_info info; + int error; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + if (!SYN_CAP_INTERTOUCH(info.ext_cap_0c)) + return -ENXIO; + + return synaptics_create_intertouch(psmouse, &info, false); +} + +#else /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +static int __maybe_unused +synaptics_setup_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + return -ENOSYS; +} + +int synaptics_init_smbus(struct psmouse *psmouse) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +#if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \ + defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS) + +int synaptics_init(struct psmouse *psmouse) +{ + struct synaptics_device_info info; + int error; + int retval; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + if (SYN_CAP_INTERTOUCH(info.ext_cap_0c)) { + error = synaptics_setup_intertouch(psmouse, &info, true); + if (!error) + return PSMOUSE_SYNAPTICS_SMBUS; + } + + retval = synaptics_setup_ps2(psmouse, &info); + if (retval < 0) { + /* + * Not using any flavor of Synaptics support, so clean up + * SMbus breadcrumbs, if any. + */ + psmouse_smbus_cleanup(psmouse); + } + + return retval; +} + +#else /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +int synaptics_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index d9b824fbddc2..31652d98b8f7 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -90,6 +90,7 @@ #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) #define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) #define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) +#define SYN_CAP_INTERTOUCH(ex0c) ((ex0c) & 0x004000) /* * The following descibes response for the 0x10 query. @@ -204,8 +205,10 @@ struct synaptics_data { void synaptics_module_init(void); int synaptics_detect(struct psmouse *psmouse, bool set_properties); -int synaptics_init(struct psmouse *psmouse); +int synaptics_init_absolute(struct psmouse *psmouse); int synaptics_init_relative(struct psmouse *psmouse); +int synaptics_init_smbus(struct psmouse *psmouse); +int synaptics_init(struct psmouse *psmouse); void synaptics_reset(struct psmouse *psmouse); #endif /* _SYNAPTICS_H */ -- cgit From f6f08c55cced6885f1e1448cd0806098e836c5f5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 1 Apr 2017 11:33:11 -0700 Subject: Input: psmouse - fix cleaning up SMBus companions When trying to destroy platform data after destruction of SMbus companion, we need to make sure that we are actually dealing with an SMB companion device, and not some random I2C client device. Fixes: 8eb92e5c9133 ("Input: psmouse - add support for SMBus companions") Reported-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-smbus.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index 061c1cc44aef..d2b1ea34feac 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -61,24 +61,29 @@ static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter) static void psmouse_smbus_detach_i2c_client(struct i2c_client *client) { - struct psmouse_smbus_dev *smbdev; + struct psmouse_smbus_dev *smbdev, *tmp; mutex_lock(&psmouse_smbus_mutex); - list_for_each_entry(smbdev, &psmouse_smbus_list, node) { - if (smbdev->client == client) { + list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { + if (smbdev->client != client) + continue; + + kfree(client->dev.platform_data); + client->dev.platform_data = NULL; + + if (!smbdev->dead) { psmouse_dbg(smbdev->psmouse, "Marking SMBus companion %s as gone\n", dev_name(&smbdev->client->dev)); - smbdev->client = NULL; smbdev->dead = true; serio_rescan(smbdev->psmouse->ps2dev.serio); + } else { + list_del(&smbdev->node); + kfree(smbdev); } } - kfree(client->dev.platform_data); - client->dev.platform_data = NULL; - mutex_unlock(&psmouse_smbus_mutex); } @@ -162,17 +167,20 @@ static void psmouse_smbus_disconnect(struct psmouse *psmouse) struct psmouse_smbus_dev *smbdev = psmouse->private; mutex_lock(&psmouse_smbus_mutex); - list_del(&smbdev->node); - mutex_unlock(&psmouse_smbus_mutex); - if (smbdev->client) { + if (smbdev->dead) { + list_del(&smbdev->node); + kfree(smbdev); + } else { + smbdev->dead = true; psmouse_dbg(smbdev->psmouse, "posting removal request for SMBus companion %s\n", dev_name(&smbdev->client->dev)); psmouse_smbus_schedule_remove(smbdev->client); } - kfree(smbdev); + mutex_unlock(&psmouse_smbus_mutex); + psmouse->private = NULL; } -- cgit From a716a026bb0d824c9ab6d6ac778c030c0030b178 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Mar 2017 10:45:13 -0700 Subject: Input: psmouse - use i2c_client_type to locate i2c clients Now that i2c_client_type structure is exported, we can use it, instead of i2c_adapter_type, when looking for devices that are i2c clients. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-smbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index d2b1ea34feac..c7ac24d119c1 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -99,7 +99,7 @@ static int psmouse_smbus_notifier_call(struct notifier_block *nb, break; case BUS_NOTIFY_REMOVED_DEVICE: - if (dev->type != &i2c_adapter_type) + if (dev->type == &i2c_client_type) psmouse_smbus_detach_i2c_client(to_i2c_client(dev)); break; } -- cgit From 2c6ecbba90d4e909bdc8982b4a2318e99d7fc4f2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 17:40:57 -0700 Subject: Input: synaptics - add synaptics_query_int() Factor out querying and parsing 3-byte response into an integer value. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 77 ++++++++++++++++------------------------- drivers/input/mouse/synaptics.h | 3 +- 2 files changed, 32 insertions(+), 48 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index d494c6c6aadc..da9ca356a7e3 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -190,6 +190,22 @@ static int synaptics_send_cmd(struct psmouse *psmouse, return 0; } +static int synaptics_query_int(struct psmouse *psmouse, u8 query_cmd, u32 *val) +{ + int error; + union { + __be32 be_val; + char buf[4]; + } resp = { 0 }; + + error = synaptics_send_cmd(psmouse, query_cmd, resp.buf + 1); + if (error) + return error; + + *val = be32_to_cpu(resp.be_val); + return 0; +} + /* * Identify Touchpad * See also the SYN_ID_* macros @@ -197,14 +213,12 @@ static int synaptics_send_cmd(struct psmouse *psmouse, static int synaptics_identify(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char id[3]; int error; - error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); + error = synaptics_query_int(psmouse, SYN_QUE_IDENTIFY, &info->identity); if (error) return error; - info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; } @@ -215,15 +229,7 @@ static int synaptics_identify(struct psmouse *psmouse, static int synaptics_model_id(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char mi[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi); - if (error) - return error; - - info->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2]; - return 0; + return synaptics_query_int(psmouse, SYN_QUE_MODEL, &info->model_id); } /* @@ -232,29 +238,8 @@ static int synaptics_model_id(struct psmouse *psmouse, static int synaptics_firmware_id(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char fwid[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); - if (error) - return error; - - info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; - return 0; -} - -static int synaptics_more_extended_queries(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - unsigned char buf[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf); - if (error) - return error; - - info->ext_cap_10 = (buf[0] << 16) | (buf[1] << 8) | buf[2]; - return 0; + return synaptics_query_int(psmouse, SYN_QUE_FIRMWARE_ID, + &info->firmware_id); } /* @@ -278,7 +263,8 @@ static int synaptics_query_modes(struct psmouse *psmouse, info->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; if (SYN_MEXT_CAP_BIT(bid[0])) - return synaptics_more_extended_queries(psmouse, info); + return synaptics_query_int(psmouse, SYN_QUE_MEXT_CAPAB_10, + &info->ext_cap_10); return 0; } @@ -290,14 +276,13 @@ static int synaptics_query_modes(struct psmouse *psmouse, static int synaptics_capability(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char cap[3]; int error; - error = synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap); + error = synaptics_query_int(psmouse, SYN_QUE_CAPABILITIES, + &info->capabilities); if (error) return error; - info->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; info->ext_cap = info->ext_cap_0c = 0; /* @@ -315,29 +300,27 @@ static int synaptics_capability(struct psmouse *psmouse, info->capabilities = 0; if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 1) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { + error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB, + &info->ext_cap); + if (error) { psmouse_warn(psmouse, "device claims to have extended capabilities, but I'm not able to read them.\n"); } else { - info->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - /* * if nExtBtn is greater than 8 it should be considered * invalid and treated as 0 */ if (SYN_CAP_MULTI_BUTTON_NO(info->ext_cap) > 8) - info->ext_cap &= 0xff0fff; + info->ext_cap &= ~SYN_CAP_MB_MASK; } } if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 4) { - error = synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap); + error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB_0C, + &info->ext_cap_0c); if (error) psmouse_warn(psmouse, "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); - else - info->ext_cap_0c = - (cap[0] << 16) | (cap[1] << 8) | cap[2]; } return 0; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 31652d98b8f7..87fbe5b53803 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -52,7 +52,8 @@ #define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) #define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8) #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) -#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) +#define SYN_CAP_MB_MASK GENMASK(15, 12) +#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & SYN_CAP_MB_MASK) >> 12) #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) #define SYN_MEXT_CAP_BIT(m) ((m) & (1 << 1)) -- cgit From 991d29fe02a767d13275b38d774cf7c35a4f4a44 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 14:56:06 -0700 Subject: Input: synaptics - use BIT() and GENMASK() macros Use standard infrastructure, such as BIT and GENMASK, instead of rolling bitmasks by hand. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 6 +-- drivers/input/mouse/synaptics.h | 90 ++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index da9ca356a7e3..26f4520f1903 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -905,9 +905,9 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, if (!SYN_CAP_EXT_BUTTONS_STICK(priv->info.ext_cap_10)) { for (i = 0; i < ext_bits; i++) { input_report_key(dev, BTN_0 + 2 * i, - hw->ext_buttons & (1 << i)); + hw->ext_buttons & BIT(i)); input_report_key(dev, BTN_1 + 2 * i, - hw->ext_buttons & (1 << (i + ext_bits))); + hw->ext_buttons & BIT(i + ext_bits)); } return; } @@ -1519,7 +1519,7 @@ static int synaptics_init_ps2(struct psmouse *psmouse, SYN_NEWABS : SYN_OLDABS; psmouse_info(psmouse, - "Touchpad model: %u, fw: %u.%u, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n", + "Touchpad model: %lu, fw: %lu.%lu, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n", SYN_ID_MODEL(info->identity), SYN_ID_MAJOR(info->identity), SYN_ID_MINOR(info->identity), info->model_id, diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 87fbe5b53803..7a998fbfa6b0 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -25,37 +25,37 @@ #define SYN_QUE_MEXT_CAPAB_10 0x10 /* synatics modes */ -#define SYN_BIT_ABSOLUTE_MODE (1 << 7) -#define SYN_BIT_HIGH_RATE (1 << 6) -#define SYN_BIT_SLEEP_MODE (1 << 3) -#define SYN_BIT_DISABLE_GESTURE (1 << 2) -#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1) -#define SYN_BIT_W_MODE (1 << 0) +#define SYN_BIT_ABSOLUTE_MODE BIT(7) +#define SYN_BIT_HIGH_RATE BIT(6) +#define SYN_BIT_SLEEP_MODE BIT(3) +#define SYN_BIT_DISABLE_GESTURE BIT(2) +#define SYN_BIT_FOUR_BYTE_CLIENT BIT(1) +#define SYN_BIT_W_MODE BIT(0) /* synaptics model ID bits */ -#define SYN_MODEL_ROT180(m) ((m) & (1 << 23)) -#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22)) -#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f) -#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f) -#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7)) -#define SYN_MODEL_PEN(m) ((m) & (1 << 6)) -#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5)) -#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f) +#define SYN_MODEL_ROT180(m) ((m) & BIT(23)) +#define SYN_MODEL_PORTRAIT(m) ((m) & BIT(22)) +#define SYN_MODEL_SENSOR(m) (((m) & GENMASK(21, 16)) >> 16) +#define SYN_MODEL_HARDWARE(m) (((m) & GENMASK(15, 9)) >> 9) +#define SYN_MODEL_NEWABS(m) ((m) & BIT(7)) +#define SYN_MODEL_PEN(m) ((m) & BIT(6)) +#define SYN_MODEL_SIMPLIC(m) ((m) & BIT(5)) +#define SYN_MODEL_GEOMETRY(m) ((m) & GENMASK(3, 0)) /* synaptics capability bits */ -#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) -#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18)) -#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) -#define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) -#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) -#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) -#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) -#define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8) -#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) +#define SYN_CAP_EXTENDED(c) ((c) & BIT(23)) +#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & BIT(18)) +#define SYN_CAP_PASS_THROUGH(c) ((c) & BIT(7)) +#define SYN_CAP_SLEEP(c) ((c) & BIT(4)) +#define SYN_CAP_FOUR_BUTTON(c) ((c) & BIT(3)) +#define SYN_CAP_MULTIFINGER(c) ((c) & BIT(1)) +#define SYN_CAP_PALMDETECT(c) ((c) & BIT(0)) +#define SYN_CAP_SUBMODEL_ID(c) (((c) & GENMASK(15, 8)) >> 8) +#define SYN_EXT_CAP_REQUESTS(c) (((c) & GENMASK(22, 20)) >> 20) #define SYN_CAP_MB_MASK GENMASK(15, 12) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & SYN_CAP_MB_MASK) >> 12) -#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) -#define SYN_MEXT_CAP_BIT(m) ((m) & (1 << 1)) +#define SYN_CAP_PRODUCT_ID(ec) (((ec) & GENMASK(23, 16)) >> 16) +#define SYN_MEXT_CAP_BIT(m) ((m) & BIT(1)) /* * The following describes response for the 0x0c query. @@ -84,14 +84,14 @@ * hinged at the top. * 2 0x20 report min query 0x0f gives min coord reported */ -#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ -#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ -#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) -#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) -#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) -#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) -#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) -#define SYN_CAP_INTERTOUCH(ex0c) ((ex0c) & 0x004000) +#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & BIT(20)) /* 1-button ClickPad */ +#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & BIT(8)) /* 2-button ClickPad */ +#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & BIT(17)) +#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & BIT(13)) +#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & BIT(19)) +#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & BIT(10)) +#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & BIT(11)) +#define SYN_CAP_INTERTOUCH(ex0c) ((ex0c) & BIT(14)) /* * The following descibes response for the 0x10 query. @@ -110,27 +110,27 @@ * 3 0xff SecurePad height the height of the SecurePad fingerprint * reader. */ -#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000) -#define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000) +#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & BIT(16)) +#define SYN_CAP_SECUREPAD(ex10) ((ex10) & BIT(17)) #define SYN_EXT_BUTTON_STICK_L(eb) (((eb) & BIT(0)) >> 0) #define SYN_EXT_BUTTON_STICK_M(eb) (((eb) & BIT(1)) >> 1) #define SYN_EXT_BUTTON_STICK_R(eb) (((eb) & BIT(2)) >> 2) /* synaptics modes query bits */ -#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) -#define SYN_MODE_RATE(m) ((m) & (1 << 6)) -#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3)) -#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2)) -#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1)) -#define SYN_MODE_WMODE(m) ((m) & (1 << 0)) +#define SYN_MODE_ABSOLUTE(m) ((m) & BIT(7)) +#define SYN_MODE_RATE(m) ((m) & BIT(6)) +#define SYN_MODE_BAUD_SLEEP(m) ((m) & BIT(3)) +#define SYN_MODE_DISABLE_GESTURE(m) ((m) & BIT(2)) +#define SYN_MODE_PACKSIZE(m) ((m) & BIT(1)) +#define SYN_MODE_WMODE(m) ((m) & BIT(0)) /* synaptics identify query bits */ -#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) -#define SYN_ID_MAJOR(i) ((i) & 0x0f) -#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) +#define SYN_ID_MODEL(i) (((i) & GENMASK(7, 4)) >> 4) +#define SYN_ID_MAJOR(i) (((i) & GENMASK(3, 0)) >> 0) +#define SYN_ID_MINOR(i) (((i) & GENMASK(23, 16)) >> 16) #define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i)) -#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) +#define SYN_ID_IS_SYNAPTICS(i) (((i) & GENMASK(15, 8)) == 0x004700U) #define SYN_ID_DISGEST_SUPPORTED(i) (SYN_ID_MAJOR(i) >= 4) /* synaptics special commands */ -- cgit From 212baf03a30a8fb29ab5f69726bb920ebe3d44a1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 18:38:14 -0700 Subject: Input: synaptics - do not abuse -1 as return value Let's stop using -1 as a universal return value and instead propagate errors from underlying calls up the stack. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 71 ++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 25 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 26f4520f1903..81ec4590003e 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -82,12 +82,17 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) { unsigned char param[1]; + int error; + + error = psmouse_sliced_command(psmouse, mode); + if (error) + return error; - if (psmouse_sliced_command(psmouse, mode)) - return -1; param[0] = SYN_PS_SET_MODE2; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) - return -1; + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE); + if (error) + return error; + return 0; } @@ -534,16 +539,19 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) { static unsigned char param = 0xc8; struct synaptics_data *priv = psmouse->private; + int error; if (!(SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c))) return 0; - if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) - return -1; + error = psmouse_sliced_command(psmouse, SYN_QUE_MODEL); + if (error) + return error; - if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE)) - return -1; + error = ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE); + if (error) + return error; /* Advanced gesture mode also sends multi finger data */ priv->info.capabilities |= BIT(1); @@ -554,6 +562,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static int synaptics_set_mode(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; + int error; priv->mode = 0; if (priv->absolute_mode) @@ -565,13 +574,18 @@ static int synaptics_set_mode(struct psmouse *psmouse) if (SYN_CAP_EXTENDED(priv->info.capabilities)) priv->mode |= SYN_BIT_W_MODE; - if (synaptics_mode_cmd(psmouse, priv->mode)) - return -1; + error = synaptics_mode_cmd(psmouse, priv->mode); + if (error) + return error; - if (priv->absolute_mode && - synaptics_set_advanced_gesture_mode(psmouse)) { - psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); - return -1; + if (priv->absolute_mode) { + error = synaptics_set_advanced_gesture_mode(psmouse); + if (error) { + psmouse_err(psmouse, + "Advanced gesture mode init failed: %d\n", + error); + return error; + } } return 0; @@ -598,12 +612,17 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) static int synaptics_pt_write(struct serio *serio, unsigned char c) { struct psmouse *parent = serio_get_drvdata(serio->parent); - char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ + u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ + int error; + + error = psmouse_sliced_command(parent, c); + if (error) + return error; + + error = ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE); + if (error) + return error; - if (psmouse_sliced_command(parent, c)) - return -1; - if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE)) - return -1; return 0; } @@ -1380,19 +1399,21 @@ static int synaptics_reconnect(struct psmouse *psmouse) } while (error && ++retry < 3); if (error) - return -1; + return error; if (retry > 1) psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); - if (synaptics_query_hardware(psmouse, &info)) { + error = synaptics_query_hardware(psmouse, &info); + if (error) { psmouse_err(psmouse, "Unable to query device.\n"); - return -1; + return error; } - if (synaptics_set_mode(psmouse)) { + error = synaptics_set_mode(psmouse); + if (error) { psmouse_err(psmouse, "Unable to initialize device.\n"); - return -1; + return error; } if (info.identity != priv->info.identity || @@ -1405,7 +1426,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) priv->info.model_id, info.model_id, priv->info.capabilities, info.capabilities, priv->info.ext_cap, info.ext_cap); - return -1; + return -ENXIO; } return 0; -- cgit From f6c4442bfa0812efbb5d54db01a17a7ba0fc9298 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Mar 2017 11:20:38 -0700 Subject: Input: synaptics - use u8 instead of unsigned char The rest of the kernel uses u8, u16, etc for data coming form hardware, let's switch ti using u8 here as well. Also turn pkt_type into an enum. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 60 ++++++++++++++++++++--------------------- drivers/input/mouse/synaptics.h | 22 ++++++++------- 2 files changed, 42 insertions(+), 40 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 81ec4590003e..131df9d3660f 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -79,9 +79,9 @@ /* * Set the synaptics touchpad mode byte by special commands */ -static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) +static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode) { - unsigned char param[1]; + u8 param[1]; int error; error = psmouse_sliced_command(psmouse, mode); @@ -99,7 +99,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) int synaptics_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; + u8 param[4]; param[0] = 0; @@ -179,12 +179,11 @@ static const char * const smbus_pnp_ids[] = { /* * Send a command to the synpatics touchpad by special commands */ -static int synaptics_send_cmd(struct psmouse *psmouse, - unsigned char c, unsigned char *param) +static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param) { int error; - error = psmouse_sliced_command(psmouse, c); + error = psmouse_sliced_command(psmouse, cmd); if (error) return error; @@ -254,7 +253,7 @@ static int synaptics_firmware_id(struct psmouse *psmouse, static int synaptics_query_modes(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char bid[3]; + u8 bid[3]; int error; /* firmwares prior 7.5 have no board_id encoded */ @@ -338,7 +337,7 @@ static int synaptics_capability(struct psmouse *psmouse, static int synaptics_resolution(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char resp[3]; + u8 resp[3]; int error; if (SYN_ID_MAJOR(info->identity) < 4) @@ -537,7 +536,7 @@ static void synaptics_apply_quirks(struct psmouse *psmouse, static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) { - static unsigned char param = 0xc8; + static u8 param = 0xc8; struct synaptics_data *priv = psmouse->private; int error; @@ -609,7 +608,7 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_write(struct serio *serio, unsigned char c) +static int synaptics_pt_write(struct serio *serio, u8 c) { struct psmouse *parent = serio_get_drvdata(serio->parent); u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ @@ -648,13 +647,12 @@ static void synaptics_pt_stop(struct serio *serio) serio_continue_rx(parent->ps2dev.serio); } -static int synaptics_is_pt_packet(unsigned char *buf) +static int synaptics_is_pt_packet(u8 *buf) { return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; } -static void synaptics_pass_pt_packet(struct serio *ptport, - unsigned char *packet) +static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet) { struct psmouse *child = serio_get_drvdata(ptport); @@ -717,7 +715,7 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ -static void synaptics_parse_agm(const unsigned char buf[], +static void synaptics_parse_agm(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { @@ -744,7 +742,7 @@ static void synaptics_parse_agm(const unsigned char buf[], } } -static void synaptics_parse_ext_buttons(const unsigned char buf[], +static void synaptics_parse_ext_buttons(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { @@ -756,7 +754,7 @@ static void synaptics_parse_ext_buttons(const unsigned char buf[], hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits; } -static int synaptics_parse_hw_state(const unsigned char buf[], +static int synaptics_parse_hw_state(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { @@ -832,7 +830,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], } else if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; if (hw->w == 2) - hw->scroll = (signed char)(buf[1]); + hw->scroll = (s8)buf[1]; } if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { @@ -1134,18 +1132,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_sync(dev); } -static int synaptics_validate_byte(struct psmouse *psmouse, - int idx, unsigned char pkt_type) +static bool synaptics_validate_byte(struct psmouse *psmouse, + int idx, enum synaptics_pkt_type pkt_type) { - static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; - static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; - static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; - const char *packet = psmouse->packet; + static const u8 newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; + static const u8 newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; + static const u8 newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; + static const u8 oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; + static const u8 oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + const u8 *packet = psmouse->packet; if (idx < 0 || idx > 4) - return 0; + return false; switch (pkt_type) { @@ -1161,19 +1159,21 @@ static int synaptics_validate_byte(struct psmouse *psmouse, default: psmouse_err(psmouse, "unknown packet type %d\n", pkt_type); - return 0; + return false; } } -static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) +static enum synaptics_pkt_type +synaptics_detect_pkt_type(struct psmouse *psmouse) { int i; - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) { if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) { psmouse_info(psmouse, "using relaxed packet validation\n"); return SYN_NEWABS_RELAXED; } + } return SYN_NEWABS_STRICT; } @@ -1378,7 +1378,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; struct synaptics_device_info info; - unsigned char param[2]; + u8 param[2]; int retry = 0; int error; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 7a998fbfa6b0..fc00e005c611 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -137,15 +137,17 @@ #define SYN_PS_SET_MODE2 0x14 #define SYN_PS_CLIENT_CMD 0x28 -/* synaptics packet types */ -#define SYN_NEWABS 0 -#define SYN_NEWABS_STRICT 1 -#define SYN_NEWABS_RELAXED 2 -#define SYN_OLDABS 3 - /* amount to fuzz position data when touchpad reports reduced filtering */ #define SYN_REDUCED_FILTER_FUZZ 8 +/* synaptics packet types */ +enum synaptics_pkt_type { + SYN_NEWABS, + SYN_NEWABS_STRICT, + SYN_NEWABS_RELAXED, + SYN_OLDABS, +}; + /* * A structure to describe the state of the touchpad hardware (buttons and pad) */ @@ -159,8 +161,8 @@ struct synaptics_hw_state { unsigned int middle:1; unsigned int up:1; unsigned int down:1; - unsigned char ext_buttons; - signed char scroll; + u8 ext_buttons; + s8 scroll; }; /* Data read from the touchpad */ @@ -181,8 +183,8 @@ struct synaptics_device_info { struct synaptics_data { struct synaptics_device_info info; - unsigned char pkt_type; /* packet type - old, new, etc */ - unsigned char mode; /* current mode byte */ + enum synaptics_pkt_type pkt_type; /* packet type - old, new, etc */ + u8 mode; /* current mode byte */ int scroll; bool absolute_mode; /* run in Absolute mode */ -- cgit