lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 7 Apr 2012 00:02:06 -0700
From:	Dmitry Torokhov <dmitry.torokhov@...il.com>
To:	Olof Johansson <olof@...om.net>, Daniel Mack <daniel@...aq.de>,
	Sven Neumann <s.neumann@...mfeld.com>,
	Daniel Mack <zonque@...il.com>
Cc:	linux-input@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH] Input: eeti_ts: Mark as CONFIG_BROKEN

Hi Olof,

On Fri, Apr 06, 2012 at 10:40:07PM -0700, Olof Johansson wrote:
> This seems to have been broken since 2010, so obviously noone actually
> cares about the driver:
> 
> make[4]: *** [drivers/input/touchscreen/eeti_ts.o] Error 1
> drivers/input/touchscreen/eeti_ts.c: In function 'eeti_ts_irq_active':
> drivers/input/touchscreen/eeti_ts.c:65:2: error: implicit declaration of function 'irq_to_gpio' [-Werror=implicit-function-declaration]
> 
> irq_to_gpio isn't available on most platforms today, so the driver
> will need some rework by someone who has hardware access and can test
> (to make sure that, for example, switching to level interrupts and just
> keep taking them while there's more to process works).
> 
> I guess it could just be scheduled for removal, but let's start with
> marking it CONFIG_BROKEN.

Well, it probably works quite well on arches that do have irq_to_gpio(),
let's ask Daniel and Sven if they still have this hardware and if they
can try the patch below that implements what you suggested.

Thanks.

-- 
Dmitry


Input: eeti_ts - do not use irq_to_gpio

From: Dmitry Torokhov <dmitry.torokhov@...il.com>

irq_to_gpio is not available on many platforms. Let's switch to using
one-shot level interrupts with threaded IRQ handlers that should stay
active as long as there is data.

Reported-by: Olof Johansson <olof@...om.net>
Signed-off-by: Dmitry Torokhov <dtor@...l.ru>
---

 drivers/input/touchscreen/eeti_ts.c |  166 ++++++++++++-----------------------
 1 files changed, 56 insertions(+), 110 deletions(-)


diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 503c709..4d875e5 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -46,9 +46,6 @@ MODULE_PARM_DESC(flip_y, "flip y coordinate");
 struct eeti_ts_priv {
 	struct i2c_client *client;
 	struct input_dev *input;
-	struct work_struct work;
-	struct mutex mutex;
-	int irq, irq_active_high;
 };
 
 #define EETI_TS_BITDEPTH	(11)
@@ -60,26 +57,18 @@ struct eeti_ts_priv {
 #define REPORT_BIT_HAS_PRESSURE	(1 << 6)
 #define REPORT_RES_BITS(v)	(((v) >> 1) + EETI_TS_BITDEPTH)
 
-static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
-{
-	return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high;
-}
-
-static void eeti_ts_read(struct work_struct *work)
+static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
 {
+	struct eeti_ts_priv *priv = dev_id;
+	struct i2c_client *client = priv->client;
+	struct input_dev *input  = priv->input;
+	unsigned int x, y, res, pressed;
+	int rc;
 	char buf[6];
-	unsigned int x, y, res, pressed, to = 100;
-	struct eeti_ts_priv *priv =
-		container_of(work, struct eeti_ts_priv, work);
-
-	mutex_lock(&priv->mutex);
-
-	while (eeti_ts_irq_active(priv) && --to)
-		i2c_master_recv(priv->client, buf, sizeof(buf));
 
-	if (!to) {
-		dev_err(&priv->client->dev,
-			"unable to clear IRQ - line stuck?\n");
+	rc = i2c_master_recv(client, buf, sizeof(buf));
+	if (rc < 0) {
+		dev_err(&client->dev, "i2c_master_recv failed, error: %d", rc);
 		goto out;
 	}
 
@@ -103,46 +92,22 @@ static void eeti_ts_read(struct work_struct *work)
 		y = EETI_MAXVAL - y;
 
 	if (buf[0] & REPORT_BIT_HAS_PRESSURE)
-		input_report_abs(priv->input, ABS_PRESSURE, buf[5]);
+		input_report_abs(input, ABS_PRESSURE, buf[5]);
 
-	input_report_abs(priv->input, ABS_X, x);
-	input_report_abs(priv->input, ABS_Y, y);
-	input_report_key(priv->input, BTN_TOUCH, !!pressed);
-	input_sync(priv->input);
+	input_report_abs(input, ABS_X, x);
+	input_report_abs(input, ABS_Y, y);
+	input_report_key(input, BTN_TOUCH, pressed);
+	input_sync(input);
 
 out:
-	mutex_unlock(&priv->mutex);
-}
-
-static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
-{
-	struct eeti_ts_priv *priv = dev_id;
-
-	 /* postpone I2C transactions as we are atomic */
-	schedule_work(&priv->work);
-
 	return IRQ_HANDLED;
 }
 
-static void eeti_ts_start(struct eeti_ts_priv *priv)
-{
-	enable_irq(priv->irq);
-
-	/* Read the events once to arm the IRQ */
-	eeti_ts_read(&priv->work);
-}
-
-static void eeti_ts_stop(struct eeti_ts_priv *priv)
-{
-	disable_irq(priv->irq);
-	cancel_work_sync(&priv->work);
-}
-
 static int eeti_ts_open(struct input_dev *dev)
 {
 	struct eeti_ts_priv *priv = input_get_drvdata(dev);
 
-	eeti_ts_start(priv);
+	enable_irq(priv->client->irq);
 
 	return 0;
 }
@@ -151,17 +116,17 @@ static void eeti_ts_close(struct input_dev *dev)
 {
 	struct eeti_ts_priv *priv = input_get_drvdata(dev);
 
-	eeti_ts_stop(priv);
+	disable_irq(priv->client->irq);
 }
 
 static int __devinit eeti_ts_probe(struct i2c_client *client,
 				   const struct i2c_device_id *idp)
 {
-	struct eeti_ts_platform_data *pdata;
+	const struct eeti_ts_platform_data *pdata = client->dev.platform_data;
 	struct eeti_ts_priv *priv;
 	struct input_dev *input;
 	unsigned int irq_flags;
-	int err = -ENOMEM;
+	int err;
 
 	/*
 	 * In contrast to what's described in the datasheet, there seems
@@ -171,25 +136,15 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
 	 */
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		dev_err(&client->dev, "failed to allocate driver data\n");
-		goto err0;
-	}
-
-	mutex_init(&priv->mutex);
 	input = input_allocate_device();
-
-	if (!input) {
-		dev_err(&client->dev, "Failed to allocate input device.\n");
-		goto err1;
+	if (!priv || !input) {
+		dev_err(&client->dev, "failed to memory\n");
+		err = -ENOMEM;
+		goto err_free_mem;
 	}
 
-	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
-	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
-	input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0);
-	input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
-	input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0);
+	priv->client = client;
+	priv->input = input;
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
@@ -197,49 +152,47 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
 	input->open = eeti_ts_open;
 	input->close = eeti_ts_close;
 
-	priv->client = client;
-	priv->input = input;
-	priv->irq = client->irq;
-
-	pdata = client->dev.platform_data;
-
-	if (pdata)
-		priv->irq_active_high = pdata->irq_active_high;
+	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
-	irq_flags = priv->irq_active_high ?
-		IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+	input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0);
 
-	INIT_WORK(&priv->work, eeti_ts_read);
-	i2c_set_clientdata(client, priv);
 	input_set_drvdata(input, priv);
 
-	err = input_register_device(input);
-	if (err)
-		goto err1;
+	irq_flags = pdata && pdata->irq_active_high ?
+			IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW;
+	irq_flags |= IRQF_ONESHOT;
 
-	err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
-			  client->name, priv);
-	if (err) {
+	err = request_threaded_irq(client->irq, NULL, eeti_ts_isr,
+				   irq_flags, client->name, priv);
+	if (err < 0) {
 		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-		goto err2;
+		goto err_free_mem;
 	}
 
 	/*
-	 * Disable the device for now. It will be enabled once the
+	 * Disable the IRQ for now. It will be enabled once the
 	 * input device is opened.
 	 */
-	eeti_ts_stop(priv);
+	disable_irq(client->irq);
 
+	err = input_register_device(input);
+	if (err)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, priv);
 	device_init_wakeup(&client->dev, 0);
+
 	return 0;
 
-err2:
-	input_unregister_device(input);
-	input = NULL; /* so we dont try to free it below */
-err1:
+err_free_irq:
+	free_irq(client->irq, priv);
+err_free_mem:
 	input_free_device(input);
 	kfree(priv);
-err0:
+
 	return err;
 }
 
@@ -247,20 +200,14 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
 {
 	struct eeti_ts_priv *priv = i2c_get_clientdata(client);
 
-	free_irq(priv->irq, priv);
-	/*
-	 * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it
-	 * so that device still works if we reload the driver.
-	 */
-	enable_irq(priv->irq);
-
+	free_irq(client->irq, priv);
 	input_unregister_device(priv->input);
 	kfree(priv);
 
 	return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int eeti_ts_suspend(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -270,12 +217,12 @@ static int eeti_ts_suspend(struct device *dev)
 	mutex_lock(&input_dev->mutex);
 
 	if (input_dev->users)
-		eeti_ts_stop(priv);
+		disable_irq(client->irq);
 
 	mutex_unlock(&input_dev->mutex);
 
 	if (device_may_wakeup(&client->dev))
-		enable_irq_wake(priv->irq);
+		enable_irq_wake(client->irq);
 
 	return 0;
 }
@@ -287,20 +234,20 @@ static int eeti_ts_resume(struct device *dev)
 	struct input_dev *input_dev = priv->input;
 
 	if (device_may_wakeup(&client->dev))
-		disable_irq_wake(priv->irq);
+		disable_irq_wake(client->irq);
 
 	mutex_lock(&input_dev->mutex);
 
 	if (input_dev->users)
-		eeti_ts_start(priv);
+		enable_irq(client->irq);
 
 	mutex_unlock(&input_dev->mutex);
 
 	return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
-#endif
 
 static const struct i2c_device_id eeti_ts_id[] = {
 	{ "eeti_ts", 0 },
@@ -311,9 +258,8 @@ MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
 static struct i2c_driver eeti_ts_driver = {
 	.driver = {
 		.name = "eeti_ts",
-#ifdef CONFIG_PM
+		.owner = THIS_MODULE,
 		.pm = &eeti_ts_pm,
-#endif
 	},
 	.probe = eeti_ts_probe,
 	.remove = __devexit_p(eeti_ts_remove),
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ