Takashi Iwai d2026c
From 6abe534f0776d2437c8302f58d8eb5abd483e926 Mon Sep 17 00:00:00 2001
Takashi Iwai d2026c
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Takashi Iwai d2026c
Date: Wed, 17 Jan 2018 15:46:18 -0800
Takashi Iwai d2026c
Subject: [PATCH] Input: synaptics-rmi4 - unmask F03 interrupts when port is opened
Takashi Iwai d2026c
Git-commit: 6abe534f0776d2437c8302f58d8eb5abd483e926
Takashi Iwai d2026c
Patch-mainline: v4.16-rc1
Takashi Iwai d2026c
References: bsc#1051510
Takashi Iwai d2026c
Takashi Iwai d2026c
Currently we register the pass-through serio port when we probe the F03 RMI
Takashi Iwai d2026c
function, and then, in sensor configure phase, we unmask interrupts.
Takashi Iwai d2026c
Unfortunately this is too late, as other drivers are free probe devices
Takashi Iwai d2026c
attached to the serio port as soon as it is probed. Because interrupts are
Takashi Iwai d2026c
masked, the IO times out, which may result in not being able to detect
Takashi Iwai d2026c
trackpoints on the pass-through port.
Takashi Iwai d2026c
Takashi Iwai d2026c
To fix the issue we implement open() and close() methods for the
Takashi Iwai d2026c
pass-through serio port and unmask interrupts from there. We also move
Takashi Iwai d2026c
creation of the pass-through port form probe to configure stage, as RMI
Takashi Iwai d2026c
driver does not enable transport interrupt until all functions are probed
Takashi Iwai d2026c
(we should change this, but this is a separate topic).
Takashi Iwai d2026c
Takashi Iwai d2026c
We also try to clear the pending data before unmasking interrupts, because
Takashi Iwai d2026c
some devices like to spam the system with multiple 0xaa 0x00 announcements,
Takashi Iwai d2026c
which may interfere with us trying to query ID of the device.
Takashi Iwai d2026c
Takashi Iwai d2026c
Fixes: c5e8848fc98e ("Input: synaptics-rmi4 - add support for F03")
Takashi Iwai d2026c
Cc: stable@vger.kernel.org
Takashi Iwai d2026c
Reviewed-by: Lyude Paul <lyude@redhat.com>
Takashi Iwai d2026c
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Takashi Iwai d2026c
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai d2026c
Takashi Iwai d2026c
---
Takashi Iwai d2026c
 drivers/input/rmi4/rmi_f03.c |   64 ++++++++++++++++++++++++++++++++++++-------
Takashi Iwai d2026c
 1 file changed, 54 insertions(+), 10 deletions(-)
Takashi Iwai d2026c
Takashi Iwai d2026c
--- a/drivers/input/rmi4/rmi_f03.c
Takashi Iwai d2026c
+++ b/drivers/input/rmi4/rmi_f03.c
Takashi Iwai d2026c
@@ -32,6 +32,7 @@ struct f03_data {
Takashi Iwai d2026c
 	struct rmi_function *fn;
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 	struct serio *serio;
Takashi Iwai d2026c
+	bool serio_registered;
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 	unsigned int overwrite_buttons;
Takashi Iwai d2026c
 
Takashi Iwai d2026c
@@ -138,6 +139,37 @@ static int rmi_f03_initialize(struct f03
Takashi Iwai d2026c
 	return 0;
Takashi Iwai d2026c
 }
Takashi Iwai d2026c
 
Takashi Iwai d2026c
+static int rmi_f03_pt_open(struct serio *serio)
Takashi Iwai d2026c
+{
Takashi Iwai d2026c
+	struct f03_data *f03 = serio->port_data;
Takashi Iwai d2026c
+	struct rmi_function *fn = f03->fn;
Takashi Iwai d2026c
+	const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
Takashi Iwai d2026c
+	const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
Takashi Iwai d2026c
+	u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
Takashi Iwai d2026c
+	int error;
Takashi Iwai d2026c
+
Takashi Iwai d2026c
+	/*
Takashi Iwai d2026c
+	 * Consume any pending data. Some devices like to spam with
Takashi Iwai d2026c
+	 * 0xaa 0x00 announcements which may confuse us as we try to
Takashi Iwai d2026c
+	 * probe the device.
Takashi Iwai d2026c
+	 */
Takashi Iwai d2026c
+	error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
Takashi Iwai d2026c
+	if (!error)
Takashi Iwai d2026c
+		rmi_dbg(RMI_DEBUG_FN, &fn->dev,
Takashi Iwai d2026c
+			"%s: Consumed %*ph (%d) from PS2 guest\n",
Takashi Iwai d2026c
+			__func__, ob_len, obs, ob_len);
Takashi Iwai d2026c
+
Takashi Iwai d2026c
+	return fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
Takashi Iwai d2026c
+}
Takashi Iwai d2026c
+
Takashi Iwai d2026c
+static void rmi_f03_pt_close(struct serio *serio)
Takashi Iwai d2026c
+{
Takashi Iwai d2026c
+	struct f03_data *f03 = serio->port_data;
Takashi Iwai d2026c
+	struct rmi_function *fn = f03->fn;
Takashi Iwai d2026c
+
Takashi Iwai d2026c
+	fn->rmi_dev->driver->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
Takashi Iwai d2026c
+}
Takashi Iwai d2026c
+
Takashi Iwai d2026c
 static int rmi_f03_register_pt(struct f03_data *f03)
Takashi Iwai d2026c
 {
Takashi Iwai d2026c
 	struct serio *serio;
Takashi Iwai d2026c
@@ -148,6 +180,8 @@ static int rmi_f03_register_pt(struct f0
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 	serio->id.type = SERIO_PS_PSTHRU;
Takashi Iwai d2026c
 	serio->write = rmi_f03_pt_write;
Takashi Iwai d2026c
+	serio->open = rmi_f03_pt_open;
Takashi Iwai d2026c
+	serio->close = rmi_f03_pt_close;
Takashi Iwai d2026c
 	serio->port_data = f03;
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 	strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
Takashi Iwai d2026c
@@ -184,17 +218,27 @@ static int rmi_f03_probe(struct rmi_func
Takashi Iwai d2026c
 			 f03->device_count);
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 	dev_set_drvdata(dev, f03);
Takashi Iwai d2026c
-
Takashi Iwai d2026c
-	error = rmi_f03_register_pt(f03);
Takashi Iwai d2026c
-	if (error)
Takashi Iwai d2026c
-		return error;
Takashi Iwai d2026c
-
Takashi Iwai d2026c
 	return 0;
Takashi Iwai d2026c
 }
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 static int rmi_f03_config(struct rmi_function *fn)
Takashi Iwai d2026c
 {
Takashi Iwai d2026c
-	fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
Takashi Iwai d2026c
+	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
Takashi Iwai d2026c
+	int error;
Takashi Iwai d2026c
+
Takashi Iwai d2026c
+	if (!f03->serio_registered) {
Takashi Iwai d2026c
+		error = rmi_f03_register_pt(f03);
Takashi Iwai d2026c
+		if (error)
Takashi Iwai d2026c
+			return error;
Takashi Iwai d2026c
+
Takashi Iwai d2026c
+		f03->serio_registered = true;
Takashi Iwai d2026c
+	} else {
Takashi Iwai d2026c
+		/*
Takashi Iwai d2026c
+		 * We must be re-configuring the sensor, just enable
Takashi Iwai d2026c
+		 * interrupts for this function.
Takashi Iwai d2026c
+		 */
Takashi Iwai d2026c
+		fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
Takashi Iwai d2026c
+	}
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 	return 0;
Takashi Iwai d2026c
 }
Takashi Iwai d2026c
@@ -204,7 +248,7 @@ static int rmi_f03_attention(struct rmi_
Takashi Iwai d2026c
 	struct rmi_device *rmi_dev = fn->rmi_dev;
Takashi Iwai d2026c
 	struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
Takashi Iwai d2026c
 	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
Takashi Iwai d2026c
-	u16 data_addr = fn->fd.data_base_addr;
Takashi Iwai d2026c
+	const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
Takashi Iwai d2026c
 	const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
Takashi Iwai d2026c
 	u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
Takashi Iwai d2026c
 	u8 ob_status;
Takashi Iwai d2026c
@@ -226,8 +270,7 @@ static int rmi_f03_attention(struct rmi_
Takashi Iwai d2026c
 		drvdata->attn_data.size -= ob_len;
Takashi Iwai d2026c
 	} else {
Takashi Iwai d2026c
 		/* Grab all of the data registers, and check them for data */
Takashi Iwai d2026c
-		error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
Takashi Iwai d2026c
-				       &obs, ob_len);
Takashi Iwai d2026c
+		error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
Takashi Iwai d2026c
 		if (error) {
Takashi Iwai d2026c
 			dev_err(&fn->dev,
Takashi Iwai d2026c
 				"%s: Failed to read F03 output buffers: %d\n",
Takashi Iwai d2026c
@@ -266,7 +309,8 @@ static void rmi_f03_remove(struct rmi_fu
Takashi Iwai d2026c
 {
Takashi Iwai d2026c
 	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
Takashi Iwai d2026c
 
Takashi Iwai d2026c
-	serio_unregister_port(f03->serio);
Takashi Iwai d2026c
+	if (f03->serio_registered)
Takashi Iwai d2026c
+		serio_unregister_port(f03->serio);
Takashi Iwai d2026c
 }
Takashi Iwai d2026c
 
Takashi Iwai d2026c
 struct rmi_function_handler rmi_f03_handler = {