From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:11:37
Hi,
Well, this is the last series which enables RMI4 over SMBus for the Thinkpad
t*40, t*50, t*60 series. Few comments on the patches:
patches 1 to 3 allows the re-routing of the trackstick buttons from the touchpad
to the trackstick
patch 4 to 7 allow rmi_smbus to actually control the PS/2 node to not resume and
mess up the configuration after a resume
patch 8 was originally sent as a RMI4 specific driver, but I came to realise
that Elan could also benefit from the same driver
patch 9 has already been sent once, but there was no clear way of enabling the
trackstick, so it was not merged
patch 10 allows the elantech driver to create an instance of elan_i2c and
forwards the trackstick information from PS/2
Note that patch 10 has only been tested on a machine without a functional
elan_i2c touchpad, so only the binding has been tested.
This series requires the Host Notify flag patch from Dmitry:
http://patchwork.ozlabs.org/patch/711229/
Cheers,
Benjamin
Benjamin Tissoires (10):
Input: serio - store the pt_buttons in the struct serio directly
Input: synaptics-rmi4 - Add rmi_find_function()
Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on
buttonpads to PS/2 guest
Input: psmouse - allow to deactivate a driver from the serio handle
Input: synaptics - allocate a Synaptics Intertouch device
Input: synaptics-rmi4 - smbus: call psmouse_deactivate before
binding/resume
Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails
Input: add a PS/2 to SMBus platform module
Input: elan_i2c - add trackstick report
Input: elantech - automatically bind an SMBus device when acceptable
drivers/input/misc/Kconfig | 11 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/ps2_smbus.c | 276 ++++++++++++++++++++++++++++++++++++
drivers/input/mouse/elan_i2c.h | 12 ++
drivers/input/mouse/elan_i2c_core.c | 99 ++++++++++++-
drivers/input/mouse/elantech.c | 54 +++++++
drivers/input/mouse/elantech.h | 3 +
drivers/input/mouse/psmouse-base.c | 34 +++++
drivers/input/mouse/psmouse.h | 3 +
drivers/input/mouse/synaptics.c | 134 +++++++++++++++--
drivers/input/mouse/synaptics.h | 5 +-
drivers/input/rmi4/Kconfig | 1 +
drivers/input/rmi4/rmi_driver.c | 13 ++
drivers/input/rmi4/rmi_driver.h | 15 ++
drivers/input/rmi4/rmi_f03.c | 30 ++++
drivers/input/rmi4/rmi_f30.c | 72 ++++++++--
drivers/input/rmi4/rmi_smbus.c | 47 ++++--
include/linux/rmi.h | 2 +
include/linux/serio.h | 22 +++
19 files changed, 795 insertions(+), 39 deletions(-)
create mode 100644 drivers/input/misc/ps2_smbus.c
--
2.9.3
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:11:39
With RMI4 over SMBus, the pass-through device can be instantiated
in a SMBus driver. However, compared to the psmouse-synaptics driver,
this pass-through PS/2 driver has no clue whether the current
serio_interrupt() is the beginning of the frame or not. Instead of
adding a protocol analysis in RMI4 function F03, we can add an extra
byte in struct serio to handle the extra data we want to append to the
first byte.
Convert the psmouse-synaptics device to use it too.
Partially reverts cdd9dc1 ("Input: synaptics - re-route tracksticks
buttons on the Lenovo 2015 series")
Acked-by: Andrew Duggan <redacted>
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/mouse/psmouse-base.c | 3 +++
drivers/input/mouse/synaptics.c | 19 ++++++++++---------
drivers/input/mouse/synaptics.h | 1 -
include/linux/serio.h | 8 ++++++++
4 files changed, 21 insertions(+), 10 deletions(-)
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:11:44
On the latest series of ThinkPads, the button events for the TrackPoint
are reported through the touchpad itself as opposed to the TrackPoint
device. In order to report these buttons properly, we need to forward
them to the TrackPoint device and send the button presses/releases
through there instead.
Signed-off-by: Lyude Paul <thatslyude@gmail.com>
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/rmi4/rmi_driver.h | 14 ++++++++
drivers/input/rmi4/rmi_f03.c | 30 +++++++++++++++++
drivers/input/rmi4/rmi_f30.c | 72 ++++++++++++++++++++++++++++++++---------
3 files changed, 101 insertions(+), 15 deletions(-)
@@ -109,6 +112,13 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)if(!f30->input)return0;+if(f30->trackstick_buttons&&!f30->f03){+f30->f03=rmi_find_function(rmi_dev,3);++if(!f30->f03)+return-EBUSY;+}+/* Read the gpi led data. */if(drvdata->attn_data.data){if(drvdata->attn_data.size<f30->register_count){
@@ -133,23 +143,29 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)for(reg_num=0;reg_num<f30->register_count;++reg_num){for(i=0;gpiled<f30->gpioled_count&&i<8;++i,++gpiled){-if(f30->gpioled_key_map[gpiled]!=0){-/* buttons have pull up resistors */-value=(((f30->data_regs[reg_num]>>i)&0x01)-==0);+/* buttons have pull up resistors */+value=(((f30->data_regs[reg_num]>>i)&0x01)==0);+if(f30->gpioled_key_map[gpiled]!=0){rmi_dbg(RMI_DEBUG_FN,&fn->dev,"%s: call input report key (0x%04x) value (0x%02x)",__func__,f30->gpioled_key_map[gpiled],value);+input_report_key(f30->input,f30->gpioled_key_map[gpiled],value);+}elseif(f30->gpio_passthrough_key_map[gpiled]){+rmi_f03_overwrite_button(f30->f03,+f30->gpio_passthrough_key_map[gpiled]-BTN_LEFT,+value);}-}}+if(f30->trackstick_buttons)+rmi_f03_commit_buttons(f30->f03);+return0;}
@@ -247,10 +263,11 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)intretval=0;intcontrol_address;inti;-intbutton;+intbutton,extra_button;u8buf[RMI_F30_QUERY_SIZE];u8*ctrl_reg;-u8*map_memory;+u8*map_memory,*pt_memory;+boolbuttonpad;f30=devm_kzalloc(&fn->dev,sizeof(structf30_data),GFP_KERNEL);
@@ -348,29 +365,54 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)map_memory=devm_kzalloc(&fn->dev,(f30->gpioled_count*(sizeof(u16))),GFP_KERNEL);-if(!map_memory){+pt_memory=devm_kzalloc(&fn->dev,+(f30->gpioled_count*(sizeof(u16))),+GFP_KERNEL);+if(!map_memory||!pt_memory){dev_err(&fn->dev,"Failed to allocate gpioled map memory.\n");return-ENOMEM;}f30->gpioled_key_map=(u16*)map_memory;+f30->gpio_passthrough_key_map=(u16*)pt_memory;pdata=rmi_get_platform_data(rmi_dev);if(f30->has_gpio){+/*+*buttonpadmightbegivenbyf30->has_mech_mouse_btns,+*butIamnotsure,souseonlythepdatainfo+*/+buttonpad=pdata->f30_data.buttonpad;+f30->trackstick_buttons=pdata->f30_data.trackstick_buttons;++/*+*Fortouchpadsthebuttonsaremappedas:+*-bit0=Left,bit1=right,bit2=middle/clickbutton+*-3,4,5areextendedbuttonsand+*-6and7areothersortsofGPIOs+*/button=BTN_LEFT;-for(i=0;i<f30->gpioled_count;i++){+extra_button=BTN_LEFT;+for(i=0;i<f30->gpioled_count&&i<3;i++){if(rmi_f30_is_valid_button(i,f30->ctrl)){f30->gpioled_key_map[i]=button++;-/*-*buttonpadmightbegivenby-*f30->has_mech_mouse_btns,butIam-*notsure,souseonlythepdatainfo-*/-if(pdata->f30_data.buttonpad)+if(buttonpad)break;}}++if(f30->trackstick_buttons){+for(i=3;i<f30->gpioled_count&&i<6;i++){+if(rmi_f30_is_valid_button(i,f30->ctrl))+f30->gpio_passthrough_key_map[i]=extra_button++;+}+}elseif(!buttonpad){+for(i=3;i<f30->gpioled_count;i++){+if(rmi_f30_is_valid_button(i,f30->ctrl))+f30->gpioled_key_map[i]=button++;+}+}}return0;
Hi Benjamin,
On Tue, Jan 10, 2017 at 05:11:21PM +0100, Benjamin Tissoires wrote:
+void rmi_f03_commit_buttons(struct rmi_function *fn)
+{
+ struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+ int i;
+
+ f03->serio->extra_byte = f03->overwrite_buttons;
+
+ for (i = 0; i < 3; i++)
+ serio_interrupt(f03->serio, 0x00, 0x00);
How does this work with protocols larger than 3 bytes (i.e. anything but
bare PS/2)? Or F03 limits the kind of devices we connect to RMI4 device?
Overall, I am very uncomfortable with the concept of "extra byte" at
serio level. Maybe we should define a new flag, something like
SERIO_SYNTHETIC or SERIO_OOB_DATA, and have something like:
void rmi_f03_commit_buttons(struct rmi_function *fn)
{
struct serio *serio = f03->serio;
serio_pause_rx(serio);
if (serio->drv) {
serio->drv->interrupt(serio, PSMOUSE_EXTRA_BTNS,
SERIO_OOB_DATA);
serio->drv->interrupt(serio, f03->overwrite_buttons.
SERIO_OOB_DATA);
}
serio_pause_rx(serio);
}
and have psmouse driver store and use it as it sees fit.
Thanks.
--
Dmitry
From: Benjamin Tissoires <hidden> Date: 2017-02-07 16:25:50
Hi Dmitry,
On Feb 06 2017 or thereabouts, Dmitry Torokhov wrote:
Hi Benjamin,
On Tue, Jan 10, 2017 at 05:11:21PM +0100, Benjamin Tissoires wrote:
quoted
+void rmi_f03_commit_buttons(struct rmi_function *fn)
+{
+ struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+ int i;
+
+ f03->serio->extra_byte = f03->overwrite_buttons;
+
+ for (i = 0; i < 3; i++)
+ serio_interrupt(f03->serio, 0x00, 0x00);
How does this work with protocols larger than 3 bytes (i.e. anything but
bare PS/2)? Or F03 limits the kind of devices we connect to RMI4 device?
Right, there is no such constraint.
Overall, I am very uncomfortable with the concept of "extra byte" at
serio level. Maybe we should define a new flag, something like
SERIO_SYNTHETIC or SERIO_OOB_DATA, and have something like:
void rmi_f03_commit_buttons(struct rmi_function *fn)
{
struct serio *serio = f03->serio;
serio_pause_rx(serio);
if (serio->drv) {
serio->drv->interrupt(serio, PSMOUSE_EXTRA_BTNS,
SERIO_OOB_DATA);
serio->drv->interrupt(serio, f03->overwrite_buttons.
SERIO_OOB_DATA);
}
serio_pause_rx(serio);
}
and have psmouse driver store and use it as it sees fit.
Sounds good to me. Would the 2 following patches be OK?
Cheers,
Benjamin
Benjamin Tissoires (2):
Input: psmouse - add a custom serio protocol to send extra information
Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on
buttonpads to PS/2 guest
drivers/input/mouse/psmouse-base.c | 39 +++++++++++++++++++--
drivers/input/mouse/psmouse.h | 5 +++
drivers/input/rmi4/rmi_driver.h | 14 ++++++++
drivers/input/rmi4/rmi_f03.c | 39 +++++++++++++++++++++
drivers/input/rmi4/rmi_f30.c | 72 ++++++++++++++++++++++++++++++--------
include/uapi/linux/serio.h | 7 ++--
6 files changed, 155 insertions(+), 21 deletions(-)
--
2.9.3
From: Benjamin Tissoires <hidden> Date: 2017-02-07 16:25:53
The tracksticks on the Lenovo thinkpads have their buttons connected
through the touchpad device. We already fixed that in synaptics.c, but
when we switch the device into RMI4 mode to have proper support, the
pass-through functionality can't deal with them easily.
We add a new PS/2 flag and protocol designed for psmouse.
The RMI4 F03 pass-through can then emit a special set of commands
to notify psmouse the state of the buttons.
This patch implements the protocol in psmouse, while an other will
do the same for rmi4-f03.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/mouse/psmouse-base.c | 39 +++++++++++++++++++++++++++++++++++---
drivers/input/mouse/psmouse.h | 5 +++++
include/uapi/linux/serio.h | 7 ++++---
3 files changed, 45 insertions(+), 6 deletions(-)
On Tue, Feb 07, 2017 at 05:25:38PM +0100, Benjamin Tissoires wrote:
The tracksticks on the Lenovo thinkpads have their buttons connected
through the touchpad device. We already fixed that in synaptics.c, but
when we switch the device into RMI4 mode to have proper support, the
pass-through functionality can't deal with them easily.
We add a new PS/2 flag and protocol designed for psmouse.
The RMI4 F03 pass-through can then emit a special set of commands
to notify psmouse the state of the buttons.
This patch implements the protocol in psmouse, while an other will
do the same for rmi4-f03.
Signed-off-by: Benjamin Tissoires <redacted>
Looks mostly good, but how about this one?
Thanks.
--
Dmitry
Input: psmouse - add a custom serio protocol to send extra information
From: Benjamin Tissoires <redacted>
The tracksticks on the Lenovo thinkpads have their buttons connected
through the touchpad device. We already fixed that in synaptics.c, but
when we switch the device into RMI4 mode to have proper support, the
pass-through functionality can't deal with them easily.
We add a new PS/2 flag and protocol designed for psmouse. The RMI4 F03
pass-through can then emit a special set of commands to notify psmouse the
state of the buttons.
This patch implements the protocol in psmouse, while an other will
do the same for rmi4-f03.
Signed-off-by: Benjamin Tissoires <redacted>
Patchwork-Id: 9560567
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/mouse/psmouse-base.c | 39 +++++++++++++++++++++++++++++++++---
drivers/input/mouse/psmouse.h | 5 +++++
include/uapi/linux/serio.h | 7 ++++--
3 files changed, 45 insertions(+), 6 deletions(-)
From: Benjamin Tissoires <hidden> Date: 2017-02-08 17:53:48
On Feb 08 2017 or thereabouts, Dmitry Torokhov wrote:
On Tue, Feb 07, 2017 at 05:25:38PM +0100, Benjamin Tissoires wrote:
quoted
The tracksticks on the Lenovo thinkpads have their buttons connected
through the touchpad device. We already fixed that in synaptics.c, but
when we switch the device into RMI4 mode to have proper support, the
pass-through functionality can't deal with them easily.
We add a new PS/2 flag and protocol designed for psmouse.
The RMI4 F03 pass-through can then emit a special set of commands
to notify psmouse the state of the buttons.
This patch implements the protocol in psmouse, while an other will
do the same for rmi4-f03.
Signed-off-by: Benjamin Tissoires <redacted>
Looks mostly good, but how about this one?
Thanks for the fix. There is one missing input_sync() in the OOB_DATA
case:
quoted hunk
Thanks.
--
Dmitry
Input: psmouse - add a custom serio protocol to send extra information
From: Benjamin Tissoires <redacted>
The tracksticks on the Lenovo thinkpads have their buttons connected
through the touchpad device. We already fixed that in synaptics.c, but
when we switch the device into RMI4 mode to have proper support, the
pass-through functionality can't deal with them easily.
We add a new PS/2 flag and protocol designed for psmouse. The RMI4 F03
pass-through can then emit a special set of commands to notify psmouse the
state of the buttons.
This patch implements the protocol in psmouse, while an other will
do the same for rmi4-f03.
Signed-off-by: Benjamin Tissoires <redacted>
Patchwork-Id: 9560567
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/mouse/psmouse-base.c | 39 +++++++++++++++++++++++++++++++++---
drivers/input/mouse/psmouse.h | 5 +++++
include/uapi/linux/serio.h | 7 ++++--
3 files changed, 45 insertions(+), 6 deletions(-)
@@ -282,6 +288,28 @@ static int psmouse_handle_byte(struct psmouse *psmouse)return0;}+staticvoidpsmouse_handle_oob_data(structpsmouse*psmouse,u8data)+{+switch(psmouse->oob_data_type){+casePSMOUSE_OOB_NONE:+psmouse->oob_data_type=data;+break;++casePSMOUSE_OOB_EXTRA_BTNS:+psmouse_report_standard_buttons(psmouse->dev,data);
We should probably call input_sync(psmouse->dev) here or the buttons are
not forwarded until the trackstick gets touched.
With that fix:
Tested-by: Benjamin Tissoires <redacted>
Cheers,
Benjamin
PS: I won't have the time to work on the other issues of the series this
week unfortunately :(
quoted hunk
+ psmouse->extra_buttons = data;
+ psmouse->oob_data_type = PSMOUSE_OOB_NONE;
+ break;
+
+ default:
+ psmouse_warn(psmouse,
+ "unknown OOB_DATA type: 0x%02x\n",
+ psmouse->oob_data_type);
+ psmouse->oob_data_type = PSMOUSE_OOB_NONE;
+ break;
+ }
+}
+
/*
* psmouse_interrupt() handles incoming characters, either passing them
* for normal processing or gathering them as command response.
From: Benjamin Tissoires <hidden> Date: 2017-02-07 16:26:03
On the latest series of ThinkPads, the button events for the TrackPoint
are reported through the touchpad itself as opposed to the TrackPoint
device. In order to report these buttons properly, we need to forward
them to the TrackPoint device and notify psmouse to send the button
presses/releases.
Signed-off-by: Lyude Paul <thatslyude@gmail.com>
Signed-off-by: Benjamin Tissoires <redacted>
---
Changes in v2:
- use of custom psmouse protocol with flag SERIO_OOB_DATA
drivers/input/rmi4/rmi_driver.h | 14 ++++++++
drivers/input/rmi4/rmi_f03.c | 39 ++++++++++++++++++++++
drivers/input/rmi4/rmi_f30.c | 72 ++++++++++++++++++++++++++++++++---------
3 files changed, 110 insertions(+), 15 deletions(-)
@@ -109,6 +112,13 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)if(!f30->input)return0;+if(f30->trackstick_buttons&&!f30->f03){+f30->f03=rmi_find_function(rmi_dev,3);++if(!f30->f03)+return-EBUSY;+}+/* Read the gpi led data. */if(drvdata->attn_data.data){if(drvdata->attn_data.size<f30->register_count){
@@ -133,23 +143,29 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)for(reg_num=0;reg_num<f30->register_count;++reg_num){for(i=0;gpiled<f30->gpioled_count&&i<8;++i,++gpiled){-if(f30->gpioled_key_map[gpiled]!=0){-/* buttons have pull up resistors */-value=(((f30->data_regs[reg_num]>>i)&0x01)-==0);+/* buttons have pull up resistors */+value=(((f30->data_regs[reg_num]>>i)&0x01)==0);+if(f30->gpioled_key_map[gpiled]!=0){rmi_dbg(RMI_DEBUG_FN,&fn->dev,"%s: call input report key (0x%04x) value (0x%02x)",__func__,f30->gpioled_key_map[gpiled],value);+input_report_key(f30->input,f30->gpioled_key_map[gpiled],value);+}elseif(f30->gpio_passthrough_key_map[gpiled]){+rmi_f03_overwrite_button(f30->f03,+f30->gpio_passthrough_key_map[gpiled]-BTN_LEFT,+value);}-}}+if(f30->trackstick_buttons)+rmi_f03_commit_buttons(f30->f03);+return0;}
@@ -247,10 +263,11 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)intretval=0;intcontrol_address;inti;-intbutton;+intbutton,extra_button;u8buf[RMI_F30_QUERY_SIZE];u8*ctrl_reg;-u8*map_memory;+u8*map_memory,*pt_memory;+boolbuttonpad;f30=devm_kzalloc(&fn->dev,sizeof(structf30_data),GFP_KERNEL);
@@ -348,29 +365,54 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)map_memory=devm_kzalloc(&fn->dev,(f30->gpioled_count*(sizeof(u16))),GFP_KERNEL);-if(!map_memory){+pt_memory=devm_kzalloc(&fn->dev,+(f30->gpioled_count*(sizeof(u16))),+GFP_KERNEL);+if(!map_memory||!pt_memory){dev_err(&fn->dev,"Failed to allocate gpioled map memory.\n");return-ENOMEM;}f30->gpioled_key_map=(u16*)map_memory;+f30->gpio_passthrough_key_map=(u16*)pt_memory;pdata=rmi_get_platform_data(rmi_dev);if(f30->has_gpio){+/*+*buttonpadmightbegivenbyf30->has_mech_mouse_btns,+*butIamnotsure,souseonlythepdatainfo+*/+buttonpad=pdata->f30_data.buttonpad;+f30->trackstick_buttons=pdata->f30_data.trackstick_buttons;++/*+*Fortouchpadsthebuttonsaremappedas:+*-bit0=Left,bit1=right,bit2=middle/clickbutton+*-3,4,5areextendedbuttonsand+*-6and7areothersortsofGPIOs+*/button=BTN_LEFT;-for(i=0;i<f30->gpioled_count;i++){+extra_button=BTN_LEFT;+for(i=0;i<f30->gpioled_count&&i<3;i++){if(rmi_f30_is_valid_button(i,f30->ctrl)){f30->gpioled_key_map[i]=button++;-/*-*buttonpadmightbegivenby-*f30->has_mech_mouse_btns,butIam-*notsure,souseonlythepdatainfo-*/-if(pdata->f30_data.buttonpad)+if(buttonpad)break;}}++if(f30->trackstick_buttons){+for(i=3;i<f30->gpioled_count&&i<6;i++){+if(rmi_f30_is_valid_button(i,f30->ctrl))+f30->gpio_passthrough_key_map[i]=extra_button++;+}+}elseif(!buttonpad){+for(i=3;i<f30->gpioled_count;i++){+if(rmi_f30_is_valid_button(i,f30->ctrl))+f30->gpioled_key_map[i]=button++;+}+}}return0;
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:11:46
If a function needs to communicate with an other, it's better to have
a way to retrieve this other.
Reviewed-by: Andrew Duggan <redacted>
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/rmi4/rmi_driver.c | 13 +++++++++++++
drivers/input/rmi4/rmi_driver.h | 1 +
2 files changed, 14 insertions(+)
On Tue, Jan 10, 2017 at 05:11:20PM +0100, Benjamin Tissoires wrote:
If a function needs to communicate with an other, it's better to have
a way to retrieve this other.
Reviewed-by: Andrew Duggan <redacted>
Signed-off-by: Benjamin Tissoires <redacted>
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:11:49
The SMBus Synaptics devices enumerated as PS/2 devices have
the problem of being deaf to I2C if the touchpad has been
fully initialized over PS/2 (psmouse_activate being called).
A simple PS/2 deactivate command is enough to make it back alive.
We forward the serio parent node to rmi_smbus so it can manually
deactivate/reactivate the serio node (so we can fallback on PS/2
if a problem happens on SMBus).
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/rmi4/rmi_smbus.c | 28 ++++++++++++++++++----------
include/linux/rmi.h | 2 ++
2 files changed, 20 insertions(+), 10 deletions(-)
@@ -244,8 +246,13 @@ static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)staticintrmi_smb_enable_smbus_mode(structrmi_smb_xport*rmi_smb){+structrmi_device_platform_data*pdata;intretval;+pdata=dev_get_platdata(&rmi_smb->client->dev);++serio_deactivate(rmi_smb->serio_parent);+/* we need to get the smbus version to activate the touchpad */retval=rmi_smb_get_version(rmi_smb);if(retval<0)
@@ -320,10 +320,13 @@ static int rmi_smb_probe(struct i2c_client *client,rmi_smb->xport.pdata.irq=client->irq;rmi_smb->xport.proto_name="smb2";rmi_smb->xport.ops=&rmi_smb_ops;+rmi_smb->serio_parent=pdata->parent;++serio_deactivate(rmi_smb->serio_parent);retval=rmi_smb_get_version(rmi_smb);if(retval<0)-returnretval;+gotofail;smbus_version=retval;rmi_dbg(RMI_DEBUG_XPORT,&client->dev,"Smbus version is %d",
@@ -332,7 +335,8 @@ static int rmi_smb_probe(struct i2c_client *client,if(smbus_version!=2){dev_err(&client->dev,"Unrecognized SMB version %d.\n",smbus_version);-return-ENODEV;+retval=-ENODEV;+gotofail;}i2c_set_clientdata(client,rmi_smb);
@@ -342,13 +346,16 @@ static int rmi_smb_probe(struct i2c_client *client,dev_err(&client->dev,"Failed to register transport driver at 0x%.2X.\n",client->addr);i2c_set_clientdata(client,NULL);-returnretval;+gotofail;}dev_info(&client->dev,"registered rmi smb driver at %#04x.\n",client->addr);return0;+fail:+serio_activate(rmi_smb->serio_parent);+returnretval;}staticintrmi_smb_remove(structi2c_client*client)
@@ -356,6 +363,7 @@ static int rmi_smb_remove(struct i2c_client *client)structrmi_smb_xport*rmi_smb=i2c_get_clientdata(client);rmi_unregister_transport_device(&rmi_smb->xport);+serio_activate(rmi_smb->serio_parent);return0;}
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:11:56
This driver is a glue between PS/2 devices that enumerate
the RMI4 devices and Elan touchpads to the RMI4 (or Elan)
SMBus driver.
We use an intermediate platform device to not add a
dependency between psmouse and I2C. It also handles
the subtleties of going around the serio mutex lock by
deferring the i2c creation/destruction in a separate
thread.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/misc/Kconfig | 11 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/ps2_smbus.c | 255 +++++++++++++++++++++++++++++++++++++++++
drivers/input/rmi4/Kconfig | 1 +
4 files changed, 268 insertions(+)
create mode 100644 drivers/input/misc/ps2_smbus.c
@@ -832,4 +832,15 @@ config INPUT_HISI_POWERKEYTocompilethisdriverasamodule,chooseMhere:themodulewillbecalledhisi_powerkey.+configPS2_SMBUS+tristate"Platform Support for PS/2 Nodes also connected over SMBus"+depends onI2C+help+SayYhereifyouwanttosupportRMI4orElandevicesconnectedto+anSMBbusbutenumeratedthroughPS/2.++ifunsure,sayN.+Tocompilethisdriverasamodule,chooseMhere:themodulewillbe+calledps2_smbus.+endif
@@ -0,0 +1,255 @@+/*+*Copyright(c)2017RedHat,Inc+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsoftheGNUGeneralPublicLicenseversion2aspublishedby+*theFreeSoftwareFoundation.+*/++#include<linux/kernel.h>+#include<linux/module.h>+#include<linux/i2c.h>+#include<linux/platform_device.h>+#include<linux/rmi.h>+#include<linux/serio.h>+#include<linux/slab.h>++MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");+MODULE_DESCRIPTION("Platform PS/2 - SMBus bridge driver");+MODULE_LICENSE("GPL");++staticstructworkqueue_struct*kps2smbus_wq;+DEFINE_MUTEX(ps2smbus_mutex);++enumps2smbus_type{+PS2SMBUS_SYNAPTICS_RMI4,+};++structps2smbus{+structi2c_client*smbus_client;+structnotifier_blocki2c_notifier;+enumps2smbus_typetype;+void*pdata;+};++enumps2smbus_event_type{+PS2SMBUS_REGISTER_DEVICE,+PS2SMBUS_UNREGISTER_DEVICE,+};++structps2smbus_work{+structwork_structwork;+enumps2smbus_event_typetype;+structps2smbus*ps2smbus;+structi2c_adapter*adap;+};++staticvoidps2smbus_create_rmi4(structps2smbus*ps2smbus,+structi2c_adapter*adap)+{+conststructi2c_board_infoi2c_info={+I2C_BOARD_INFO("rmi4_smbus",0x2c),+.platform_data=ps2smbus->pdata,+.flags=I2C_CLIENT_HOST_NOTIFY,+};++ps2smbus->smbus_client=i2c_new_device(adap,&i2c_info);+}++staticvoidps2smbus_worker(structwork_struct*work)+{+structps2smbus_work*ps2smbus_work;+structi2c_client*client;++ps2smbus_work=container_of(work,structps2smbus_work,work);+client=ps2smbus_work->ps2smbus->smbus_client;++mutex_lock(&ps2smbus_mutex);++switch(ps2smbus_work->type){+casePS2SMBUS_REGISTER_DEVICE:+if(ps2smbus_work->ps2smbus->type==PS2SMBUS_SYNAPTICS_RMI4)+ps2smbus_create_rmi4(ps2smbus_work->ps2smbus,+ps2smbus_work->adap);+break;+casePS2SMBUS_UNREGISTER_DEVICE:+if(client)+i2c_unregister_device(client);+break;+}++kfree(ps2smbus_work);++mutex_unlock(&ps2smbus_mutex);+}++staticintps2smbus_schedule_work(enumps2smbus_event_typetype,+structps2smbus*ps2smbus,+structi2c_adapter*adap)+{+structps2smbus_work*ps2smbus_work;++ps2smbus_work=kzalloc(sizeof(*ps2smbus_work),GFP_KERNEL);+if(!ps2smbus_work)+return-ENOMEM;++ps2smbus_work->type=type;+ps2smbus_work->ps2smbus=ps2smbus;+ps2smbus_work->adap=adap;++INIT_WORK(&ps2smbus_work->work,ps2smbus_worker);++queue_work(kps2smbus_wq,&ps2smbus_work->work);++return0;+}++staticintps2smbus_attach_i2c_device(structdevice*dev,void*data)+{+structps2smbus*ps2smbus=data;+structi2c_adapter*adap;++if(dev->type!=&i2c_adapter_type)+return0;++adap=to_i2c_adapter(dev);++if(!i2c_check_functionality(adap,I2C_FUNC_SMBUS_HOST_NOTIFY))+return0;++if(ps2smbus->smbus_client)+return0;++ps2smbus_schedule_work(PS2SMBUS_REGISTER_DEVICE,ps2smbus,adap);++pr_debug("ps2smbus: adapter [%s] registered\n",adap->name);+return0;+}++staticintps2smbus_detach_i2c_device(structdevice*dev,+structps2smbus*ps2smbus)+{+structi2c_client*client;++if(dev->type==&i2c_adapter_type)+return0;++mutex_lock(&ps2smbus_mutex);++client=to_i2c_client(dev);+if(client==ps2smbus->smbus_client)+ps2smbus->smbus_client=NULL;++mutex_unlock(&ps2smbus_mutex);++pr_debug("ps2smbus: client [%s] unregistered\n",client->name);+return0;+}++staticintps2smbus_notifier_call(structnotifier_block*nb,+unsignedlongaction,void*data)+{+structdevice*dev=data;+structps2smbus*ps2smbus;++ps2smbus=container_of(nb,structps2smbus,i2c_notifier);++switch(action){+caseBUS_NOTIFY_ADD_DEVICE:+returnps2smbus_attach_i2c_device(dev,ps2smbus);+caseBUS_NOTIFY_DEL_DEVICE:+returnps2smbus_detach_i2c_device(dev,ps2smbus);+}++return0;+}++staticintps2smbus_probe(structplatform_device*pdev)+{+structrmi_device_platform_data*rmi_pdata=pdev->dev.platform_data;+structserio*parent;+structps2smbus*ps2smbus;+interror;++ps2smbus=devm_kzalloc(&pdev->dev,sizeof(structps2smbus),+GFP_KERNEL);+if(!ps2smbus)+return-ENOMEM;++ps2smbus->i2c_notifier.notifier_call=ps2smbus_notifier_call;+ps2smbus->pdata=pdev->dev.platform_data;+ps2smbus->type=pdev->id_entry->driver_data;+if(pdev->dev.parent){+parent=to_serio_port(pdev->dev.parent);+if(ps2smbus->type==PS2SMBUS_SYNAPTICS_RMI4)+rmi_pdata->parent=parent;+}++/* Keep track of adapters which will be added or removed later */+error=bus_register_notifier(&i2c_bus_type,&ps2smbus->i2c_notifier);+if(error)+returnerror;++/* Bind to already existing adapters right away */+i2c_for_each_dev(ps2smbus,ps2smbus_attach_i2c_device);++platform_set_drvdata(pdev,ps2smbus);++return0;+}++staticintps2smbus_remove(structplatform_device*pdev)+{+structps2smbus*ps2smbus=platform_get_drvdata(pdev);++bus_unregister_notifier(&i2c_bus_type,&ps2smbus->i2c_notifier);++if(ps2smbus->smbus_client)+ps2smbus_schedule_work(PS2SMBUS_UNREGISTER_DEVICE,ps2smbus,+NULL);++platform_set_drvdata(pdev,NULL);++return0;+}++staticconststructplatform_device_idps2smbus_id_table[]={+{.name="rmi4",.driver_data=PS2SMBUS_SYNAPTICS_RMI4},+{}+};+MODULE_DEVICE_TABLE(platform,ps2smbus_id_table);++staticstructplatform_driverps2smbus_drv={+.driver={+.name="ps2smbus",+},+.probe=ps2smbus_probe,+.remove=ps2smbus_remove,+.id_table=ps2smbus_id_table,+};++staticint__initps2smbus_init(void)+{+interr;++kps2smbus_wq=alloc_ordered_workqueue("kps2smbusd",WQ_MEM_RECLAIM);+if(!kps2smbus_wq){+pr_err("failed to create kps2smbusd workqueue\n");+return-ENOMEM;+}++err=platform_driver_register(&ps2smbus_drv);+if(err)+destroy_workqueue(kps2smbus_wq);++returnerr;+}++staticvoid__exitps2smbus_exit(void)+{+platform_driver_unregister(&ps2smbus_drv);+destroy_workqueue(kps2smbus_wq);+}++module_init(ps2smbus_init);+module_exit(ps2smbus_exit);
From: Benjamin Tissoires <hidden> Date: 2017-01-18 08:06:31
On Tue, Jan 10, 2017 at 5:11 PM, Benjamin Tissoires
[off-list ref] wrote:
quoted hunk
This driver is a glue between PS/2 devices that enumerate
the RMI4 devices and Elan touchpads to the RMI4 (or Elan)
SMBus driver.
We use an intermediate platform device to not add a
dependency between psmouse and I2C. It also handles
the subtleties of going around the serio mutex lock by
deferring the i2c creation/destruction in a separate
thread.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/misc/Kconfig | 11 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/ps2_smbus.c | 255 +++++++++++++++++++++++++++++++++++++++++
drivers/input/rmi4/Kconfig | 1 +
4 files changed, 268 insertions(+)
create mode 100644 drivers/input/misc/ps2_smbus.c
@@ -832,4 +832,15 @@ config INPUT_HISI_POWERKEYTocompilethisdriverasamodule,chooseMhere:themodulewillbecalledhisi_powerkey.+configPS2_SMBUS+tristate"Platform Support for PS/2 Nodes also connected over SMBus"+depends onI2C+help+SayYhereifyouwanttosupportRMI4orElandevicesconnectedto+anSMBbusbutenumeratedthroughPS/2.++ifunsure,sayN.+Tocompilethisdriverasamodule,chooseMhere:themodulewillbe+calledps2_smbus.+endif
@@ -0,0 +1,255 @@+/*+*Copyright(c)2017RedHat,Inc+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsoftheGNUGeneralPublicLicenseversion2aspublishedby+*theFreeSoftwareFoundation.+*/++#include<linux/kernel.h>+#include<linux/module.h>+#include<linux/i2c.h>+#include<linux/platform_device.h>+#include<linux/rmi.h>+#include<linux/serio.h>+#include<linux/slab.h>++MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");+MODULE_DESCRIPTION("Platform PS/2 - SMBus bridge driver");+MODULE_LICENSE("GPL");++staticstructworkqueue_struct*kps2smbus_wq;+DEFINE_MUTEX(ps2smbus_mutex);++enumps2smbus_type{+PS2SMBUS_SYNAPTICS_RMI4,+};++structps2smbus{+structi2c_client*smbus_client;+structnotifier_blocki2c_notifier;+enumps2smbus_typetype;+void*pdata;+};++enumps2smbus_event_type{+PS2SMBUS_REGISTER_DEVICE,+PS2SMBUS_UNREGISTER_DEVICE,+};++structps2smbus_work{+structwork_structwork;+enumps2smbus_event_typetype;+structps2smbus*ps2smbus;+structi2c_adapter*adap;+};++staticvoidps2smbus_create_rmi4(structps2smbus*ps2smbus,+structi2c_adapter*adap)+{+conststructi2c_board_infoi2c_info={+I2C_BOARD_INFO("rmi4_smbus",0x2c),+.platform_data=ps2smbus->pdata,+.flags=I2C_CLIENT_HOST_NOTIFY,+};++ps2smbus->smbus_client=i2c_new_device(adap,&i2c_info);+}++staticvoidps2smbus_worker(structwork_struct*work)+{+structps2smbus_work*ps2smbus_work;+structi2c_client*client;++ps2smbus_work=container_of(work,structps2smbus_work,work);+client=ps2smbus_work->ps2smbus->smbus_client;++mutex_lock(&ps2smbus_mutex);++switch(ps2smbus_work->type){+casePS2SMBUS_REGISTER_DEVICE:+if(ps2smbus_work->ps2smbus->type==PS2SMBUS_SYNAPTICS_RMI4)+ps2smbus_create_rmi4(ps2smbus_work->ps2smbus,+ps2smbus_work->adap);+break;+casePS2SMBUS_UNREGISTER_DEVICE:+if(client)+i2c_unregister_device(client);+break;+}++kfree(ps2smbus_work);++mutex_unlock(&ps2smbus_mutex);+}++staticintps2smbus_schedule_work(enumps2smbus_event_typetype,+structps2smbus*ps2smbus,+structi2c_adapter*adap)+{+structps2smbus_work*ps2smbus_work;++ps2smbus_work=kzalloc(sizeof(*ps2smbus_work),GFP_KERNEL);+if(!ps2smbus_work)+return-ENOMEM;++ps2smbus_work->type=type;+ps2smbus_work->ps2smbus=ps2smbus;+ps2smbus_work->adap=adap;++INIT_WORK(&ps2smbus_work->work,ps2smbus_worker);++queue_work(kps2smbus_wq,&ps2smbus_work->work);++return0;+}++staticintps2smbus_attach_i2c_device(structdevice*dev,void*data)+{+structps2smbus*ps2smbus=data;+structi2c_adapter*adap;++if(dev->type!=&i2c_adapter_type)+return0;++adap=to_i2c_adapter(dev);++if(!i2c_check_functionality(adap,I2C_FUNC_SMBUS_HOST_NOTIFY))+return0;++if(ps2smbus->smbus_client)+return0;++ps2smbus_schedule_work(PS2SMBUS_REGISTER_DEVICE,ps2smbus,adap);++pr_debug("ps2smbus: adapter [%s] registered\n",adap->name);+return0;+}++staticintps2smbus_detach_i2c_device(structdevice*dev,+structps2smbus*ps2smbus)+{+structi2c_client*client;++if(dev->type==&i2c_adapter_type)+return0;++mutex_lock(&ps2smbus_mutex);++client=to_i2c_client(dev);+if(client==ps2smbus->smbus_client)+ps2smbus->smbus_client=NULL;++mutex_unlock(&ps2smbus_mutex);++pr_debug("ps2smbus: client [%s] unregistered\n",client->name);+return0;+}++staticintps2smbus_notifier_call(structnotifier_block*nb,+unsignedlongaction,void*data)+{+structdevice*dev=data;+structps2smbus*ps2smbus;++ps2smbus=container_of(nb,structps2smbus,i2c_notifier);++switch(action){+caseBUS_NOTIFY_ADD_DEVICE:+returnps2smbus_attach_i2c_device(dev,ps2smbus);+caseBUS_NOTIFY_DEL_DEVICE:+returnps2smbus_detach_i2c_device(dev,ps2smbus);+}++return0;+}++staticintps2smbus_probe(structplatform_device*pdev)+{+structrmi_device_platform_data*rmi_pdata=pdev->dev.platform_data;+structserio*parent;+structps2smbus*ps2smbus;+interror;++ps2smbus=devm_kzalloc(&pdev->dev,sizeof(structps2smbus),+GFP_KERNEL);+if(!ps2smbus)+return-ENOMEM;++ps2smbus->i2c_notifier.notifier_call=ps2smbus_notifier_call;+ps2smbus->pdata=pdev->dev.platform_data;+ps2smbus->type=pdev->id_entry->driver_data;+if(pdev->dev.parent){+parent=to_serio_port(pdev->dev.parent);+if(ps2smbus->type==PS2SMBUS_SYNAPTICS_RMI4)+rmi_pdata->parent=parent;+}++/* Keep track of adapters which will be added or removed later */+error=bus_register_notifier(&i2c_bus_type,&ps2smbus->i2c_notifier);+if(error)+returnerror;++/* Bind to already existing adapters right away */+i2c_for_each_dev(ps2smbus,ps2smbus_attach_i2c_device);++platform_set_drvdata(pdev,ps2smbus);++return0;+}++staticintps2smbus_remove(structplatform_device*pdev)+{+structps2smbus*ps2smbus=platform_get_drvdata(pdev);++bus_unregister_notifier(&i2c_bus_type,&ps2smbus->i2c_notifier);++if(ps2smbus->smbus_client)+ps2smbus_schedule_work(PS2SMBUS_UNREGISTER_DEVICE,ps2smbus,+NULL);++platform_set_drvdata(pdev,NULL);++return0;+}++staticconststructplatform_device_idps2smbus_id_table[]={+{.name="rmi4",.driver_data=PS2SMBUS_SYNAPTICS_RMI4},+{}+};+MODULE_DEVICE_TABLE(platform,ps2smbus_id_table);++staticstructplatform_driverps2smbus_drv={+.driver={+.name="ps2smbus",+},+.probe=ps2smbus_probe,+.remove=ps2smbus_remove,+.id_table=ps2smbus_id_table,+};++staticint__initps2smbus_init(void)+{+interr;++kps2smbus_wq=alloc_ordered_workqueue("kps2smbusd",WQ_MEM_RECLAIM);+if(!kps2smbus_wq){+pr_err("failed to create kps2smbusd workqueue\n");+return-ENOMEM;+}++err=platform_driver_register(&ps2smbus_drv);+if(err)+destroy_workqueue(kps2smbus_wq);++returnerr;+}++staticvoid__exitps2smbus_exit(void)+{+platform_driver_unregister(&ps2smbus_drv);+destroy_workqueue(kps2smbus_wq);+}++module_init(ps2smbus_init);+module_exit(ps2smbus_exit);
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:12:11
In the same way Synaptics devices can use a secondary bus with a better
bandwidth, Elantech touchpads can also be talked over SMBus.
It's unclear right now which devices have this capability, so use a module
parameter to enable/disable this. We can then whitelist them until we find
a more reliable way of detecting them.
When provided, elan_i2c also prevents the PS/2 node from resuming by
calling serio_deactivate().
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/misc/ps2_smbus.c | 23 +++++++++++++++-
drivers/input/mouse/elan_i2c.h | 2 ++
drivers/input/mouse/elan_i2c_core.c | 8 ++++++
drivers/input/mouse/elantech.c | 54 +++++++++++++++++++++++++++++++++++++
drivers/input/mouse/elantech.h | 3 +++
5 files changed, 89 insertions(+), 1 deletion(-)
@@ -1092,6 +1093,7 @@ static int elan_probe(struct i2c_client *client,conststructelan_transport_ops*transport_ops;structdevice*dev=&client->dev;structelan_tp_data*data;+structserio*parent=NULL;unsignedlongirqflags;boolhas_trackpoint=pdata&&pdata->trackpoint;interror;
@@ -1122,6 +1124,12 @@ static int elan_probe(struct i2c_client *client,init_completion(&data->fw_completion);mutex_init(&data->sysfs_mutex);+if(pdata)+parent=pdata->parent;++/* Make sure the driver stays here on resume */+serio_deactivate(parent);+data->vcc=devm_regulator_get(&client->dev,"vcc");if(IS_ERR(data->vcc)){error=PTR_ERR(data->vcc);
@@ -16,11 +16,28 @@#include<linux/module.h>#include<linux/input.h>#include<linux/input/mt.h>+#include<linux/platform_device.h>#include<linux/serio.h>#include<linux/libps2.h>#include<asm/unaligned.h>#include"psmouse.h"#include"elantech.h"+#include"elan_i2c.h"++/*+*ThenewestElandevicescanuseasecondarybus(overSMBus)which+*providesabetterbandwidthandallowabettercontrolofthetouchpads.+*Thisisusedtodecideifweneedtousethisbusornot.+*/+enum{+ELAN_SMBUS_NOT_SET=-1,+ELAN_SMBUS_OFF,+ELAN_SMBUS_ON,+};++staticintelan_smbus=ELAN_SMBUS_OFF;+module_param_named(elan_smbus,elan_smbus,int,0644);+MODULE_PARM_DESC(elan_smbus,"Use a secondary bus for the Elantech device.");#define elantech_debug(fmt, ...) \do{\
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:12:38
The Elan touchpads over I2C/SMBus also can handle a
trackstick. Unfortunately, nothing tells us if the
device supports trackstick (the information lies in
the PS/2 node), so rely on a platform data to enable
or not the trackstick node.
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313939
Signed-off-by: Benjamin Tissoires <redacted>
---
changes in v2:
- renamed ETP_PT_REPORT_ID into ETP_TP_REPORT_ID (pass-through to track-point)
to stay more in line with the rest
- removed Host Notify support so amended to match parent
---
drivers/input/mouse/elan_i2c.h | 10 ++++
drivers/input/mouse/elan_i2c_core.c | 91 +++++++++++++++++++++++++++++++++++--
2 files changed, 98 insertions(+), 3 deletions(-)
@@ -912,6 +914,34 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)input_sync(input);}+staticvoidelan_report_trackpoint(structelan_tp_data*data,u8*report)+{+structinput_dev*input=data->tp_input;+u8*packet=&report[ETP_REPORT_ID_OFFSET+1];+intx,y;++if(!data->tp_input){+dev_warn_once(&data->client->dev,+"received a trackpoint report while no trackpoint device has been created.\n"+"Please report upstream.\n");+return;+}++input_report_key(input,BTN_LEFT,packet[0]&0x01);+input_report_key(input,BTN_RIGHT,packet[0]&0x02);+input_report_key(input,BTN_MIDDLE,packet[0]&0x04);++if((packet[3]&0x0F)==0x06){+x=packet[4]-(int)((packet[1]^0x80)<<1);+y=(int)((packet[2]^0x80)<<1)-packet[5];++input_report_rel(input,REL_X,x);+input_report_rel(input,REL_Y,y);+}++input_sync(input);+}+staticirqreturn_telan_isr(intirq,void*dev_id){structelan_tp_data*data=dev_id;
@@ -933,11 +963,17 @@ static irqreturn_t elan_isr(int irq, void *dev_id)if(error)gotoout;-if(report[ETP_REPORT_ID_OFFSET]!=ETP_REPORT_ID)+switch(report[ETP_REPORT_ID_OFFSET]){+caseETP_REPORT_ID:+elan_report_absolute(data,report);+break;+caseETP_TP_REPORT_ID:+elan_report_trackpoint(data,report);+break;+default:dev_err(dev,"invalid report id data (%x)\n",report[ETP_REPORT_ID_OFFSET]);-else-elan_report_absolute(data,report);+}out:returnIRQ_HANDLED;
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:12:59
In some rare cases, we can't retrieve the SMBus version and so we fail
binding the touchpad back. Instead of leaving a touchpad dead, try again
to reinitialize it.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/rmi4/rmi_smbus.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
@@ -265,10 +265,27 @@ static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr){structrmi_smb_xport*rmi_smb=container_of(xport,structrmi_smb_xport,xport);+structi2c_client*client=rmi_smb->client;+inttries,ret;rmi_smb_clear_state(rmi_smb);-returnrmi_smb_enable_smbus_mode(rmi_smb);+for(tries=3;tries>0;tries--){+ret=rmi_smb_enable_smbus_mode(rmi_smb);+if(!ret)+break;++/* we failed enabling SMBus, try again later */+msleep(500);+}++if(ret<0){+dev_warn(&client->dev,+"failed to enable SMBus mode, giving up.\n");+serio_activate(rmi_smb->serio_parent);+}++returnret;}staticconststructrmi_transport_opsrmi_smb_ops={
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:13:22
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.
When we encounter such a device, we can create a platform device with
the information gathered through the PS/2 enumeration as some information
might be missing through the other bus. Using a platform device allows
to not add any dependency on the psmouse driver.
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.
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. We need to be sure the psmouse
driver will stop communicating with the device (and the pass-through
trackstick too). This part is not addressed here but will be in a
following patch.
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 <redacted>
---
drivers/input/mouse/synaptics.c | 100 ++++++++++++++++++++++++++++++++++++++++
drivers/input/mouse/synaptics.h | 4 ++
2 files changed, 104 insertions(+)
@@ -70,6 +72,21 @@/* maximum ABS_MT_POSITION displacement (in mm) */#define DMAX 10+/*+*ThenewestSynapticsdevicecanuseasecondarybus(calledInterTouch)which+*providesabetterbandwidthandallowabettercontrolofthetouchpads.+*Thisisusedtodecideifweneedtousethisbusornot.+*/+enum{+SYNAPTICS_INTERTOUCH_NOT_SET=-1,+SYNAPTICS_INTERTOUCH_OFF,+SYNAPTICS_INTERTOUCH_ON,+};++staticintsynaptics_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.");+/******************************************************************************StuffweneedevenwhenwedonotwantnativeSynapticssupport****************************************************************************/
@@ -218,6 +235,81 @@ static const char * const forcepad_pnp_ids[] = {NULL};+staticconstchar*constsmbus_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 */+};++staticintrmi4_id;++staticintsynaptics_create_intertouch(structpsmouse*psmouse)+{+structsynaptics_data*priv=psmouse->private;+structplatform_device_infopdevinfo;+structplatform_device*pdev;+structrmi_device_platform_datapdata={+.sensor_pdata={+.sensor_type=rmi_sensor_touchpad,+.axis_align.flip_y=true,+/* to prevent cursors jumps: */+.kernel_tracking=true,+},+.f30_data={+.buttonpad=SYN_CAP_CLICKPAD(priv->ext_cap_0c),+.trackstick_buttons=+!!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10),+},+};++if(priv->intertouch)+return-EINVAL;++pdata.sensor_pdata.topbuttonpad=+psmouse_matches_pnp_id(psmouse,topbuttonpad_pnp_ids)&&+!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10);++memset(&pdevinfo,0,sizeof(pdevinfo));+pdevinfo.name="rmi4";+pdevinfo.id=rmi4_id++;+pdevinfo.data=&pdata;+pdevinfo.size_data=sizeof(pdata);+pdevinfo.parent=&psmouse->ps2dev.serio->dev;++pdev=platform_device_register_full(&pdevinfo);+if(IS_ERR(pdev))+returnPTR_ERR(pdev);++priv->intertouch=pdev;++return0;+}++/**+*synaptics_setup_intertouch-calledoncethePS/2devicesareenumerated+*anddecidestoinstantiateaSMBusInterTouchdevice.+*/+staticvoidsynaptics_setup_intertouch(structpsmouse*psmouse)+{+intret;++if(synaptics_intertouch==SYNAPTICS_INTERTOUCH_OFF)+return;++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;+}++psmouse_info(psmouse,"device also supported by an other bus.\n");+ret=synaptics_create_intertouch(psmouse);+if(ret)+psmouse_info(psmouse,+"unable to create intertouch device.\n");+}/******************************************************************************Synapticscommunicationsfunctions****************************************************************************/
From: Benjamin Tissoires <hidden> Date: 2017-01-10 16:13:49
The RMI4 over SMBus and PS/2 implementation of Synaptics touchpads are
mutually exclusive. We need a way to deactivate the touchpad from the PS/2
node and prevent it to not rebind itself during resume.
Signed-off-by: Benjamin Tissoires <redacted>
---
drivers/input/mouse/psmouse-base.c | 31 +++++++++++++++++++++++++++++++
drivers/input/mouse/psmouse.h | 3 +++
drivers/input/mouse/synaptics.c | 15 +++++++++++++++
include/linux/serio.h | 14 ++++++++++++++
4 files changed, 63 insertions(+)
@@ -1518,6 +1531,8 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)psmouse->disconnect=synaptics_disconnect;psmouse->reconnect=synaptics_reconnect;psmouse->cleanup=synaptics_reset;+psmouse->activate=synaptics_activate;+psmouse->activate=synaptics_deactivate;/* Synaptics can usually stay in sync without extra help */psmouse->resync_time=0;
From: Benjamin Tissoires <hidden> Date: 2017-01-30 13:06:27
Hi Dmitri,
On Tue, Jan 10, 2017 at 5:11 PM, Benjamin Tissoires
[off-list ref] wrote:
Hi,
Well, this is the last series which enables RMI4 over SMBus for the Thinkpad
t*40, t*50, t*60 series. Few comments on the patches:
patches 1 to 3 allows the re-routing of the trackstick buttons from the touchpad
to the trackstick
patch 4 to 7 allow rmi_smbus to actually control the PS/2 node to not resume and
mess up the configuration after a resume
patch 8 was originally sent as a RMI4 specific driver, but I came to realise
that Elan could also benefit from the same driver
Any comments on the first 8 patches?
Cheers,
Benjamin
patch 9 has already been sent once, but there was no clear way of enabling the
trackstick, so it was not merged
patch 10 allows the elantech driver to create an instance of elan_i2c and
forwards the trackstick information from PS/2
Note that patch 10 has only been tested on a machine without a functional
elan_i2c touchpad, so only the binding has been tested.
This series requires the Host Notify flag patch from Dmitry:
http://patchwork.ozlabs.org/patch/711229/
Cheers,
Benjamin
Benjamin Tissoires (10):
Input: serio - store the pt_buttons in the struct serio directly
Input: synaptics-rmi4 - Add rmi_find_function()
Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on
buttonpads to PS/2 guest
Input: psmouse - allow to deactivate a driver from the serio handle
Input: synaptics - allocate a Synaptics Intertouch device
Input: synaptics-rmi4 - smbus: call psmouse_deactivate before
binding/resume
Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails
Input: add a PS/2 to SMBus platform module
Input: elan_i2c - add trackstick report
Input: elantech - automatically bind an SMBus device when acceptable
drivers/input/misc/Kconfig | 11 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/ps2_smbus.c | 276 ++++++++++++++++++++++++++++++++++++
drivers/input/mouse/elan_i2c.h | 12 ++
drivers/input/mouse/elan_i2c_core.c | 99 ++++++++++++-
drivers/input/mouse/elantech.c | 54 +++++++
drivers/input/mouse/elantech.h | 3 +
drivers/input/mouse/psmouse-base.c | 34 +++++
drivers/input/mouse/psmouse.h | 3 +
drivers/input/mouse/synaptics.c | 134 +++++++++++++++--
drivers/input/mouse/synaptics.h | 5 +-
drivers/input/rmi4/Kconfig | 1 +
drivers/input/rmi4/rmi_driver.c | 13 ++
drivers/input/rmi4/rmi_driver.h | 15 ++
drivers/input/rmi4/rmi_f03.c | 30 ++++
drivers/input/rmi4/rmi_f30.c | 72 ++++++++--
drivers/input/rmi4/rmi_smbus.c | 47 ++++--
include/linux/rmi.h | 2 +
include/linux/serio.h | 22 +++
19 files changed, 795 insertions(+), 39 deletions(-)
create mode 100644 drivers/input/misc/ps2_smbus.c
--
2.9.3
Hi Benjamin,
On Mon, Jan 30, 2017 at 02:05:39PM +0100, Benjamin Tissoires wrote:
Hi Dmitri,
On Tue, Jan 10, 2017 at 5:11 PM, Benjamin Tissoires
[off-list ref] wrote:
quoted
Hi,
Well, this is the last series which enables RMI4 over SMBus for the Thinkpad
t*40, t*50, t*60 series. Few comments on the patches:
patches 1 to 3 allows the re-routing of the trackstick buttons from the touchpad
to the trackstick
patch 4 to 7 allow rmi_smbus to actually control the PS/2 node to not resume and
mess up the configuration after a resume
patch 8 was originally sent as a RMI4 specific driver, but I came to realise
that Elan could also benefit from the same driver
Any comments on the first 8 patches?
I think that by trying to "unwind" unsuccessful SMbus initialization you
make the code much more complicated and fragile. I think we should
select a path (PS/2 or SMbus) and commit to it. If we commit to SMBus
then we need to communicate that fact to psmouse core so that it does
not create input devices or psmouse attributes, and "short-circuit" the
reconnect() routines to simply ignore requests and always report
success.
Thanks.
--
Dmitry