diff options
Diffstat (limited to 'drivers/input/rmi4')
-rw-r--r-- | drivers/input/rmi4/rmi_f03.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c index 24c7375aa361..7a3ec0ed0c27 100644 --- a/drivers/input/rmi4/rmi_f03.c +++ b/drivers/input/rmi4/rmi_f03.c @@ -163,6 +163,7 @@ static int rmi_f03_config(struct rmi_function *fn) static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits) { + struct rmi_device *rmi_dev = fn->rmi_dev; struct f03_data *f03 = dev_get_drvdata(&fn->dev); u16 data_addr = fn->fd.data_base_addr; const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE; @@ -173,15 +174,31 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits) int i; int error; - /* 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); - if (error) { - dev_err(&fn->dev, - "%s: Failed to read F03 output buffers: %d\n", - __func__, error); - serio_interrupt(f03->serio, 0, SERIO_TIMEOUT); - return error; + if (!rmi_dev || !rmi_dev->xport) + return -ENODEV; + + if (rmi_dev->xport->attn_data) { + /* First grab the data passed by the transport device */ + if (rmi_dev->xport->attn_size < ob_len) { + dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n"); + return 0; + } + + memcpy(obs, rmi_dev->xport->attn_data, ob_len); + + rmi_dev->xport->attn_data += ob_len; + rmi_dev->xport->attn_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); + if (error) { + dev_err(&fn->dev, + "%s: Failed to read F03 output buffers: %d\n", + __func__, error); + serio_interrupt(f03->serio, 0, SERIO_TIMEOUT); + return error; + } } for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) { |