summaryrefslogtreecommitdiff
path: root/drivers/input/rmi4/rmi_driver.c
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2016-12-02 17:48:51 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2016-12-02 17:51:31 -0800
commitb908d3cd812abe3f4a74d7550bbf0a8cbcfbe6ed (patch)
treeee455c7a27dc2dbb32a0b5c6689998fc90597e1d /drivers/input/rmi4/rmi_driver.c
parente621132f934f5922e8a3968edd236f97cdad60cf (diff)
Input: synaptics-rmi4 - allow to add attention data
The HID implementation of RMI4 provides the data during the interrupt (in the input report). We need to provide a way for this transport driver to provide the attention data while calling an IRQ. We use a fifo in rmi_core to not lose any incoming event. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Reviewed-by: Andrew Duggan <aduggan@synaptics.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/rmi4/rmi_driver.c')
-rw-r--r--drivers/input/rmi4/rmi_driver.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index a718e51afb0b..85062e414e73 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -191,16 +191,53 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
return 0;
}
+void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
+ void *data, size_t size)
+{
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data;
+ void *fifo_data;
+
+ if (!drvdata->enabled)
+ return;
+
+ fifo_data = kmemdup(data, size, GFP_ATOMIC);
+ if (!fifo_data)
+ return;
+
+ attn_data.irq_status = irq_status;
+ attn_data.size = size;
+ attn_data.data = fifo_data;
+
+ kfifo_put(&drvdata->attn_fifo, attn_data);
+}
+EXPORT_SYMBOL_GPL(rmi_set_attn_data);
+
static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
{
struct rmi_device *rmi_dev = dev_id;
- int ret;
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data = {0};
+ int ret, count;
+
+ count = kfifo_get(&drvdata->attn_fifo, &attn_data);
+ if (count) {
+ *(drvdata->irq_status) = attn_data.irq_status;
+ rmi_dev->xport->attn_data = attn_data.data;
+ rmi_dev->xport->attn_size = attn_data.size;
+ }
ret = rmi_process_interrupt_requests(rmi_dev);
if (ret)
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
"Failed to process interrupt request: %d\n", ret);
+ if (count)
+ kfree(attn_data.data);
+
+ if (!kfifo_is_empty(&drvdata->attn_fifo))
+ return rmi_irq_fn(irq, dev_id);
+
return IRQ_HANDLED;
}
@@ -880,8 +917,9 @@ void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
{
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi4_attn_data attn_data = {0};
int irq = pdata->irq;
- int retval;
+ int retval, count;
mutex_lock(&data->enabled_mutex);
@@ -898,6 +936,13 @@ void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
retval);
}
+ /* make sure the fifo is clean */
+ while (!kfifo_is_empty(&data->attn_fifo)) {
+ count = kfifo_get(&data->attn_fifo, &attn_data);
+ if (count)
+ kfree(attn_data.data);
+ }
+
out:
mutex_unlock(&data->enabled_mutex);
}