Skip to content

Commit

Permalink
Input: synaptics-rmi4 - unmask F03 interrupts when port is opened
Browse files Browse the repository at this point in the history
BugLink: http://bugs.launchpad.net/bugs/1747169

commit 6abe534 upstream.

Currently we register the pass-through serio port when we probe the F03 RMI
function, and then, in sensor configure phase, we unmask interrupts.
Unfortunately this is too late, as other drivers are free probe devices
attached to the serio port as soon as it is probed. Because interrupts are
masked, the IO times out, which may result in not being able to detect
trackpoints on the pass-through port.

To fix the issue we implement open() and close() methods for the
pass-through serio port and unmask interrupts from there. We also move
creation of the pass-through port form probe to configure stage, as RMI
driver does not enable transport interrupt until all functions are probed
(we should change this, but this is a separate topic).

We also try to clear the pending data before unmasking interrupts, because
some devices like to spam the system with multiple 0xaa 0x00 announcements,
which may interfere with us trying to query ID of the device.

Fixes: c5e8848 ("Input: synaptics-rmi4 - add support for F03")
Reviewed-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
  • Loading branch information
Dmitry Torokhov authored and Seth Forshee committed Feb 3, 2018
1 parent a5befdc commit d539bf9
Showing 1 changed file with 54 additions and 10 deletions.
64 changes: 54 additions & 10 deletions drivers/input/rmi4/rmi_f03.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct f03_data {
struct rmi_function *fn;

struct serio *serio;
bool serio_registered;

unsigned int overwrite_buttons;

Expand Down Expand Up @@ -138,6 +139,37 @@ static int rmi_f03_initialize(struct f03_data *f03)
return 0;
}

static int rmi_f03_pt_open(struct serio *serio)
{
struct f03_data *f03 = serio->port_data;
struct rmi_function *fn = f03->fn;
const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
int error;

/*
* Consume any pending data. Some devices like to spam with
* 0xaa 0x00 announcements which may confuse us as we try to
* probe the device.
*/
error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
if (!error)
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
"%s: Consumed %*ph (%d) from PS2 guest\n",
__func__, ob_len, obs, ob_len);

return fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
}

static void rmi_f03_pt_close(struct serio *serio)
{
struct f03_data *f03 = serio->port_data;
struct rmi_function *fn = f03->fn;

fn->rmi_dev->driver->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
}

static int rmi_f03_register_pt(struct f03_data *f03)
{
struct serio *serio;
Expand All @@ -148,6 +180,8 @@ static int rmi_f03_register_pt(struct f03_data *f03)

serio->id.type = SERIO_PS_PSTHRU;
serio->write = rmi_f03_pt_write;
serio->open = rmi_f03_pt_open;
serio->close = rmi_f03_pt_close;
serio->port_data = f03;

strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
Expand Down Expand Up @@ -184,17 +218,27 @@ static int rmi_f03_probe(struct rmi_function *fn)
f03->device_count);

dev_set_drvdata(dev, f03);

error = rmi_f03_register_pt(f03);
if (error)
return error;

return 0;
}

static int rmi_f03_config(struct rmi_function *fn)
{
fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
int error;

if (!f03->serio_registered) {
error = rmi_f03_register_pt(f03);
if (error)
return error;

f03->serio_registered = true;
} else {
/*
* We must be re-configuring the sensor, just enable
* interrupts for this function.
*/
fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
}

return 0;
}
Expand All @@ -204,7 +248,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
u16 data_addr = fn->fd.data_base_addr;
const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
u8 ob_status;
Expand All @@ -226,8 +270,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
drvdata->attn_data.size -= ob_len;
} else {
/* Grab all of the data registers, and check them for data */
error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
&obs, ob_len);
error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
if (error) {
dev_err(&fn->dev,
"%s: Failed to read F03 output buffers: %d\n",
Expand Down Expand Up @@ -266,7 +309,8 @@ static void rmi_f03_remove(struct rmi_function *fn)
{
struct f03_data *f03 = dev_get_drvdata(&fn->dev);

serio_unregister_port(f03->serio);
if (f03->serio_registered)
serio_unregister_port(f03->serio);
}

struct rmi_function_handler rmi_f03_handler = {
Expand Down

0 comments on commit d539bf9

Please sign in to comment.