Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [BUG] Kmemleak, possibly hiddev_connect(), in 6.3.0+ torvalds tree commit gfc4354c6e5c2
From: Mirsad Goran Todorovac @ 2023-05-12 19:08 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Mirsad Goran Todorovac
  Cc: linux-usb, linux-kernel, linux-input, Benjamin Tissoires,
	Jiri Kosina
In-Reply-To: <2023050958-precut-vividly-94bf@gregkh>

Hi, Greg,

On 09. 05. 2023. 04:59, Greg Kroah-Hartman wrote:
> On Tue, May 09, 2023 at 01:51:35AM +0200, Mirsad Goran Todorovac wrote:
>>
>>
>> On 08. 05. 2023. 16:01, Greg Kroah-Hartman wrote:
>>> On Mon, May 08, 2023 at 08:51:55AM +0200, Greg Kroah-Hartman wrote:
>>>> On Mon, May 08, 2023 at 08:30:07AM +0200, Mirsad Goran Todorovac wrote:
>>>>> Hi,
>>>>>
>>>>> There seems to be a kernel memory leak in the USB keyboard driver.
>>>>>
>>>>> The leaked memory allocs are 96 and 512 bytes.
>>>>>
>>>>> The platform is Ubuntu 22.04 LTS on a assembled AMD Ryzen 9 with X670E PG
>>>>> Lightning mobo,
>>>>> and Genius SlimStar i220 GK-080012 keyboard.
>>>>>
>>>>> (Logitech M100 HID mouse is not affected by the bug.)
>>>>>
>>>>> BIOS is:
>>>>>
>>>>>        *-firmware
>>>>>             description: BIOS
>>>>>             vendor: American Megatrends International, LLC.
>>>>>             physical id: 0
>>>>>             version: 1.21
>>>>>             date: 04/26/2023
>>>>>             size: 64KiB
>>>>>
>>>>> The kernel is 6.3.0-torvalds-<id>-13466-gfc4354c6e5c2.
>>>>>
>>>>> The keyboard is recognised as Chicony:
>>>>>
>>>>>                    *-usb
>>>>>                         description: Keyboard
>>>>>                         product: CHICONY USB Keyboard
>>>>>                         vendor: CHICONY
>>>>>                         physical id: 2
>>>>>                         bus info: usb@5:2
>>>>>                         logical name: input35
>>>>>                         logical name: /dev/input/event4
>>>>>                         logical name: input35::capslock
>>>>>                         logical name: input35::numlock
>>>>>                         logical name: input35::scrolllock
>>>>>                         logical name: input36
>>>>>                         logical name: /dev/input/event5
>>>>>                         logical name: input37
>>>>>                         logical name: /dev/input/event6
>>>>>                         logical name: input38
>>>>>                         logical name: /dev/input/event8
>>>>>                         version: 2.30
>>>>>                         capabilities: usb-2.00 usb
>>>>>                         configuration: driver=usbhid maxpower=100mA
>>>>> speed=1Mbit/s
>>>>>
>>>>> The bug is easily reproduced by unplugging the USB keyboard, waiting about a
>>>>> couple of seconds,
>>>>> and then reconnect and scan for memory leaks twice.
>>>>>
>>>>> The kmemleak log is as follows [edited privacy info]:
>>>>>
>>>>> root@hostname:/home/username# cat /sys/kernel/debug/kmemleak
>>>>> unreferenced object 0xffff8dd020037c00 (size 96):
>>>>>     comm "systemd-udevd", pid 435, jiffies 4294892550 (age 8909.356s)
>>>>>     hex dump (first 32 bytes):
>>>>>       5d 8e 4e b9 ff ff ff ff 00 00 00 00 00 00 00 00 ].N.............
>>>>>       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
>>>>>     backtrace:
>>>>>       [<ffffffffb81a74be>] __kmem_cache_alloc_node+0x22e/0x2b0
>>>>>       [<ffffffffb8127b6e>] kmalloc_trace+0x2e/0xa0
>>>>>       [<ffffffffb87543d9>] class_create+0x29/0x80
>>>>>       [<ffffffffb8880d24>] usb_register_dev+0x1d4/0x2e0
>>>>
>>>> As the call to class_create() in this path is now gone in 6.4-rc1, can
>>>> you retry that release to see if this is still there or not?
>>>
>>> No, wait, it's still there, I was looking at a development branch of
>>> mine that isn't sent upstream yet.  And syzbot just reported the same
>>> thing:
>>> 	https://lore.kernel.org/r/00000000000058d15f05fb264013@google.com
>>>
>>> So something's wrong here, let me dig into it tomorrow when I get a
>>> chance...
>>
>> If this could help, here is the bisect of the bug (I could not discern what
>> could possibly be wrong):
>>
>> user@host:~/linux/kernel/linux_torvalds$ git bisect log
>> git bisect start
>> # bad: [ac9a78681b921877518763ba0e89202254349d1b] Linux 6.4-rc1
>> git bisect bad ac9a78681b921877518763ba0e89202254349d1b
>> # good: [c9c3395d5e3dcc6daee66c6908354d47bf98cb0c] Linux 6.2
>> git bisect good c9c3395d5e3dcc6daee66c6908354d47bf98cb0c
>> # good: [85496c9b3bf8dbe15e2433d3a0197954d323cadc] Merge branch
>> 'net-remove-some-rcu_bh-cruft'
>> git bisect good 85496c9b3bf8dbe15e2433d3a0197954d323cadc
>> # good: [b68ee1c6131c540a62ecd443be89c406401df091] Merge tag 'scsi-misc' of
>> git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
>> git bisect good b68ee1c6131c540a62ecd443be89c406401df091
>> # bad: [888d3c9f7f3ae44101a3fd76528d3dd6f96e9fd0] Merge tag 'sysctl-6.4-rc1'
>> of git://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux
>> git bisect bad 888d3c9f7f3ae44101a3fd76528d3dd6f96e9fd0
>> # good: [34b62f186db9614e55d021f8c58d22fc44c57911] Merge tag
>> 'pci-v6.4-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
>> git bisect good 34b62f186db9614e55d021f8c58d22fc44c57911
>> # good: [34da76dca4673ab1819830b4924bb5b436325b26] Merge tag
>> 'for-linus-2023042601' of
>> git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
>> git bisect good 34da76dca4673ab1819830b4924bb5b436325b26
>> # good: [97b2ff294381d05e59294a931c4db55276470cb5] Merge tag
>> 'staging-6.4-rc1' of
>> git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
>> git bisect good 97b2ff294381d05e59294a931c4db55276470cb5
>> # good: [2025b2ca8004c04861903d076c67a73a0ec6dfca] mcb-lpc: Reallocate
>> memory region to avoid memory overlapping
>> git bisect good 2025b2ca8004c04861903d076c67a73a0ec6dfca
>> # bad: [d06f5a3f7140921ada47d49574ae6fa4de5e2a89] cdx: fix build failure due
>> to sysfs 'bus_type' argument needing to be const
>> git bisect bad d06f5a3f7140921ada47d49574ae6fa4de5e2a89
>> # good: [dcfbb67e48a2becfce7990386e985b9c45098ee5] driver core: class: use
>> lock_class_key already present in struct subsys_private
>> git bisect good dcfbb67e48a2becfce7990386e985b9c45098ee5
>> # bad: [6f14c02220c791d5c46b0f965b9340c58f3d503d] driver core: create
>> class_is_registered()
>> git bisect bad 6f14c02220c791d5c46b0f965b9340c58f3d503d
>> # good: [2f9e87f5a2941b259336c7ea6c5a1499ede4554a] driver core: Add a
>> comment to set_primary_fwnode() on nullifying
>> git bisect good 2f9e87f5a2941b259336c7ea6c5a1499ede4554a
>> # bad: [02fe26f25325b547b7a31a65deb0326c04bb5174] firmware_loader: Add debug
>> message with checksum for FW file
>> git bisect bad 02fe26f25325b547b7a31a65deb0326c04bb5174
>> # good: [884f8ce42ccec9d0bf11d8bf9f111e5961ca1c82] driver core: class:
>> implement class_get/put without the private pointer.
>> git bisect good 884f8ce42ccec9d0bf11d8bf9f111e5961ca1c82
>> # bad: [3f84aa5ec052dba960baca4ab8a352d43d47028e] base: soc: populate
>> machine name in soc_device_register if empty
>> git bisect bad 3f84aa5ec052dba960baca4ab8a352d43d47028e
>> # bad: [7b884b7f24b42fa25e92ed724ad82f137610afaf] driver core: class.c:
>> convert to only use class_to_subsys
>> git bisect bad 7b884b7f24b42fa25e92ed724ad82f137610afaf
>> # first bad commit: [7b884b7f24b42fa25e92ed724ad82f137610afaf] driver core:
>> class.c: convert to only use class_to_subsys
>> user@host:~/linux/kernel/linux_torvalds$
> 
> This helps a lot, thanks.  I got the reference counting wrong somewhere
> in here, I thought I tested this better, odd it shows up now...
> 
> I'll try to work on it this week.
> 
> thanks,
> 
> greg k-h

Not at all!

I hope you had better luck because this part of code still looks to me 
like hieroglyphs.

Linux kernel rose to 10.9M lines, and it would take me thirty years to
just read it once, 1000 lines a day ... 6.7M lines are "just drivers".

# find . -name '*.c' -o -name '*.h' -print0 | wc --files0-from -
10913623 35587483 631377958 total
# find drivers -name '*.c' -o -name '*.h' -print0 | wc --files0-from -
6705084 19985060 495162001 total

Best regards,
Mirsad

^ permalink raw reply

* [PATCH] Input: pwm-beeper - Support volume setting via sysfs
From: Marek Vasut @ 2023-05-12 18:55 UTC (permalink / raw)
  To: linux-input
  Cc: Marek Vasut, Uwe Kleine-König, Dmitry Torokhov,
	Frieder Schrempf, Manuel Traut, Thierry Reding, linux-pwm

The PWM beeper volume can be controlled by adjusting the PWM duty cycle,
expose volume setting via sysfs, so users can make the beeper quieter.
This patch adds sysfs attribute 'volume' in range 0..50000, i.e. from 0
to 50% in 1/1000th of percent steps, this resolution should be sufficient.

The reason for 50000 cap on volume or PWM duty cycle is because duty cycle
above 50% again reduces the loudness, the PWM wave form is inverted wave
form of the one for duty cycle below 50% and the beeper gets quieter the
closer the setting is to 100% . Hence, 50% cap where the wave form yields
the loudest result.

Signed-off-by: Marek Vasut <marex@denx.de>
---
An alternative option would be to extend the userspace input ABI, e.g. by
using SND_TONE top 16bits to encode the duty cycle in 0..50000 range, and
bottom 16bit to encode the existing frequency in Hz . Since frequency in
Hz is likely to be below some 25 kHz for audible bell, this fits in 16bits
just fine. Thoughts ?
---
NOTE: This uses approach similar to [1], except it is much simpler.
      [1] https://patchwork.kernel.org/project/linux-input/cover/20230201152128.614439-1-manuel.traut@mt.com/
---
Cc: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Frieder Schrempf <frieder.schrempf@kontron.de>
Cc: Manuel Traut <manuel.traut@mt.com>
Cc: Marek Vasut <marex@denx.de>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: linux-input@vger.kernel.org
Cc: linux-pwm@vger.kernel.org
---
 drivers/input/misc/pwm-beeper.c | 58 ++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 3cf1812384e6a..f63d0ebbaf573 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -21,6 +21,7 @@ struct pwm_beeper {
 	struct regulator *amplifier;
 	struct work_struct work;
 	unsigned long period;
+	unsigned long duty_cycle;
 	unsigned int bell_frequency;
 	bool suspended;
 	bool amplifier_on;
@@ -37,7 +38,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
 
 	state.enabled = true;
 	state.period = period;
-	pwm_set_relative_duty_cycle(&state, 50, 100);
+	pwm_set_relative_duty_cycle(&state, beeper->duty_cycle, 100000);
 
 	error = pwm_apply_state(beeper->pwm, &state);
 	if (error)
@@ -119,6 +120,53 @@ static void pwm_beeper_close(struct input_dev *input)
 	pwm_beeper_stop(beeper);
 }
 
+static ssize_t volume_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "%ld\n", beeper->duty_cycle);
+}
+
+static ssize_t volume_store(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+	unsigned long val;
+
+	if (kstrtoul(buf, 0, &val) < 0)
+		return -EINVAL;
+
+	/*
+	 * Volume is really PWM duty cycle in pcm (per cent mille, 1/1000th
+	 * of percent). This value therefore ranges from 0 to 50000 . Duty
+	 * cycle of 50% = 50000pcm is the maximum volume .
+	 */
+	val = clamp(val, 0UL, 50000UL);
+	/* No change in current settings, do nothing. */
+	if (val == beeper->duty_cycle)
+		return count;
+
+	/* Update current settings and apply to PWM chip. */
+	beeper->duty_cycle = val;
+	if (!beeper->suspended)
+		schedule_work(&beeper->work);
+
+	return count;
+}
+static DEVICE_ATTR_RW(volume);
+
+static struct attribute *pwm_beeper_dev_attrs[] = {
+	&dev_attr_volume.attr,
+	NULL
+};
+
+static const struct attribute_group pwm_beeper_attr_group = {
+	.attrs = pwm_beeper_dev_attrs,
+};
+
 static int pwm_beeper_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -192,6 +240,14 @@ static int pwm_beeper_probe(struct platform_device *pdev)
 
 	input_set_drvdata(beeper->input, beeper);
 
+	beeper->duty_cycle = 50000;
+	error = devm_device_add_group(dev, &pwm_beeper_attr_group);
+	if (error) {
+		dev_err(dev, "Unable to create sysfs attributes: %d\n",
+			error);
+		return error;
+	}
+
 	error = input_register_device(beeper->input);
 	if (error) {
 		dev_err(dev, "Failed to register input device: %d\n", error);
-- 
2.39.2


^ permalink raw reply related

* Re: [PATCH v5] Fix freeze in lm8333 i2c keyboard driver
From: Jeff LaBundy @ 2023-05-12 17:28 UTC (permalink / raw)
  To: Tomáš Mudruňka; +Cc: Dmitry Torokhov, linux-input, linux-kernel
In-Reply-To: <CAH2-hcJ8XxK060O-QCCBz+=cKk1HbT-aOKQH2EOY=D=xttvz7A@mail.gmail.com>

Hi Tomas,

On Fri, May 12, 2023 at 06:55:08PM +0200, Tomáš Mudruňka wrote:
> > So this is still racy, isn't it? The interrupt may come after read is
> > done, but before we register the handler.
> 
> Well. It is. But please see the rest of the thread, where we've
> already discussed this.
> 
> Every time the interrupt handler runs, the interrupt is disabled and
> then reenabled after i2c communication is done. Which means this exact
> thing happens on each keypress anyway. So i don't think it's a
> necessarily huge deal. It might not be perfect solution, but it makes
> things much better. window in which the deadlock condition can happen
> is now in range of few ms (or us), instead of ~10 seconds (previously
> it included bootloader and basicaly any moment from power up to driver
> load)

Right, but the point is that there are some alternatives to reduce the
range to zero. You posted one already, but I mistakenly advised against
it due to my own oversight :)

> 
> Another solution would be to trigger on LOW instead of FALLING as
> proposed in initial version of the patch. That would be safer in terms
> of lm8333 deadlock, but Jeff was concerned about possibility of
> interrupt storm taking down whole system in case the IRQ line gets
> stuck in LOW for some reason...

Just to clarify, this is not my concern; all bets are off in case of
gross hardware failure such as this. Rather, my recommendations are:

1. Level (or edge) sensitivity should be specified in dts, not hard-coded
in the driver.

2. If you open support for level-triggered interrupts, you should verify
on a scope whether there is any chance that the IRQ line may still be in
the process of rising at the moment the read is completed. The datasheet
is ambiguous here.

> 
> Tom
> 
> pá 12. 5. 2023 v 1:44 odesílatel Dmitry Torokhov
> <dmitry.torokhov@gmail.com> napsal:
> >
> > On Wed, May 03, 2023 at 08:44:06PM -0500, Jeff LaBundy wrote:
> > > Hi Tomas,
> > >
> > > On Wed, May 03, 2023 at 05:32:31PM +0200, Tomas Mudrunka wrote:
> > > > LM8333 uses gpio interrupt line which is triggered by falling edge.
> > > > When button is pressed before driver is loaded,
> > > > driver will miss the edge and never respond again.
> > > > To fix this we run the interrupt handler before registering IRQ
> > > > to clear the interrupt via i2c command.
> > > >
> > > > Signed-off-by: Tomas Mudrunka <tomas.mudrunka@gmail.com>
> > > > ---
> > >
> > > Reviewed-by: Jeff LaBundy <jeff@labundy.com>
> > >
> > > >  drivers/input/keyboard/lm8333.c | 2 ++
> > > >  1 file changed, 2 insertions(+)
> > > >
> > > > diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
> > > > index 7457c3220..52108c370 100644
> > > > --- a/drivers/input/keyboard/lm8333.c
> > > > +++ b/drivers/input/keyboard/lm8333.c
> > > > @@ -178,6 +178,8 @@ static int lm8333_probe(struct i2c_client *client)
> > > >                     dev_warn(&client->dev, "Unable to set active time\n");
> > > >     }
> > > >
> > > > +   lm8333_irq_thread(client->irq, lm8333);
> >
> > So this is still racy, isn't it? The interrupt may come after read is
> > done, but before we register the handler.
> >
> > > > +
> > > >     err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
> > > >                                IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> > > >                                "lm8333", lm8333);
> > > > --
> > > > 2.40.1
> > >
> >
> > Thanks.
> >
> > --
> > Dmitry

Kind regards,
Jeff LaBundy

^ permalink raw reply

* Re: [PATCH v3 2/5] Input: add driver for Focaltech FTS touchscreen
From: Jeff LaBundy @ 2023-05-12 17:00 UTC (permalink / raw)
  To: Joel Selvaraj
  Cc: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Markuss Broks, Jean Delvare,
	Max Krummenacher, Chris Morgan, Job Noorman, Alistair Francis,
	Hans de Goede, Maxime Ripard, linux-input, devicetree,
	linux-kernel, linux-arm-msm, ~postmarketos/upstreaming,
	phone-devel
In-Reply-To: <e25468f4-e3a3-bcf7-c2c0-826edb0600c2@gmail.com>

Hi Joel,

On Thu, May 11, 2023 at 07:43:28PM -0500, Joel Selvaraj wrote:
> Hi Jeff LaBundy,
> 
> On 4/23/23 21:39, Jeff LaBundy wrote:
> > Hi Joel,
> > 
> > Great work so far! It's coming along nicely. Please find my latest
> > feedback below.
> 
> Sorry for the late reply, university semester end got me hooked up.
> I have a sad kind of good news... As pointed out by Hans de Goede, the
> edt-ft5x06 driver works out of the box for the fts8719 touchscreen in my
> device. So I think this patch series is no longer needed. I did have a look
> at the driver once when working on this patch series, but it looked
> different/not compatible at that time. After mentioned by Hans de Goede, I
> had a more closer look and the main touch buffer handling seems to be the
> same.
> 
> I am sorry as we put some considerable time in this patch series. I should
> have noted more carefully. Thank you though as I learnt things working on
> this patch series.

There is absolutely no need to apologize; the review process is just as
informative for the reviewer as it is the reviewee. The important thing
is that the most optimal solution lands. "Less code is the best code" :)

> 
> I guess I will send a different patch to add the compatible data to the
> existing edt-ft5x06 driver and dts changes to include that driver to my
> device.

Sounds great.

> 
> > On Fri, Apr 14, 2023 at 09:02:19PM -0500, Joel Selvaraj wrote:
> > > The Focaltech FTS driver supports several variants of focaltech
> > > touchscreens found in ~2018 era smartphones including variants found on
> > > the PocoPhone F1 and the SHIFT6mq which are already present in mainline.
> > > This driver is loosely based on the original driver from Focaltech
> > > but has been simplified and largely reworked.
> > > 
> > > Co-developed-by: Caleb Connolly <caleb@connolly.tech>
> > > Signed-off-by: Caleb Connolly <caleb@connolly.tech>
> > > Signed-off-by: Joel Selvaraj <joelselvaraj.oss@gmail.com>
> > > ---
> > >   MAINTAINERS                                   |   8 +
> > >   drivers/input/touchscreen/Kconfig             |  12 +
> > >   drivers/input/touchscreen/Makefile            |   1 +
> > >   drivers/input/touchscreen/focaltech_fts5452.c | 432 ++++++++++++++++++
> > >   4 files changed, 453 insertions(+)
> > >   create mode 100644 drivers/input/touchscreen/focaltech_fts5452.c
> > > 
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index 7ec4ce64f66d..1a3ea61e1f52 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -8028,6 +8028,14 @@ L:	linux-input@vger.kernel.org
> > >   S:	Maintained
> > >   F:	drivers/input/joystick/fsia6b.c
> > > +FOCALTECH FTS5452 TOUCHSCREEN DRIVER
> > > +M:	Joel Selvaraj <joelselvaraj.oss@gmail.com>
> > > +M:	Caleb Connolly <caleb@connolly.tech>
> > > +L:	linux-input@vger.kernel.org
> > > +S:	Maintained
> > > +F:	Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml
> > > +F:	drivers/input/touchscreen/focaltech_fts5452.c
> > > +
> > >   FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER
> > >   M:	Geoffrey D. Bennett <g@b4.vu>
> > >   L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
> > > diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> > > index 1feecd7ed3cb..11af91504969 100644
> > > --- a/drivers/input/touchscreen/Kconfig
> > > +++ b/drivers/input/touchscreen/Kconfig
> > > @@ -388,6 +388,18 @@ config TOUCHSCREEN_EXC3000
> > >   	  To compile this driver as a module, choose M here: the
> > >   	  module will be called exc3000.
> > > +config TOUCHSCREEN_FOCALTECH_FTS5452
> > > +	tristate "Focaltech FTS Touchscreen"
> > > +	depends on I2C
> > > +	help
> > > +	  Say Y here to enable support for I2C connected Focaltech FTS
> > > +	  based touch panels, including the 5452 and 8917 panels.
> > 
> > This language is a bit misleading, as it seems to suggest three or more
> > models are supported. It seems the title should simply be "FocalTech
> > FTS5452 touchscreen controller" with the description as "...FocalTech
> > FTS5452 and compatible touchscreen controllers."
> > 
> > As more are found to be compatible (e.g. FTS8917), the compatible strings
> > can simply be appended.
> > 
> > > +
> > > +	  If unsure, say N.
> > > +
> > > +	  To compile this driver as a module, choose M here: the
> > > +	  module will be called focaltech_fts.
> > > +
> > >   config TOUCHSCREEN_FUJITSU
> > >   	tristate "Fujitsu serial touchscreen"
> > >   	select SERIO
> > > diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> > > index 159cd5136fdb..47d78c9cff21 100644
> > > --- a/drivers/input/touchscreen/Makefile
> > > +++ b/drivers/input/touchscreen/Makefile
> > > @@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
> > >   obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
> > >   obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)	+= egalax_ts_serial.o
> > >   obj-$(CONFIG_TOUCHSCREEN_EXC3000)	+= exc3000.o
> > > +obj-$(CONFIG_TOUCHSCREEN_FOCALTECH_FTS5452)	+= focaltech_fts5452.o
> > >   obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
> > >   obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix_ts.o
> > >   obj-$(CONFIG_TOUCHSCREEN_HIDEEP)	+= hideep.o
> > > diff --git a/drivers/input/touchscreen/focaltech_fts5452.c b/drivers/input/touchscreen/focaltech_fts5452.c
> > > new file mode 100644
> > > index 000000000000..abf8a2f271ca
> > > --- /dev/null
> > > +++ b/drivers/input/touchscreen/focaltech_fts5452.c
> > > @@ -0,0 +1,432 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * FocalTech touchscreen driver.
> > > + *
> > > + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved.
> > > + * Copyright (C) 2018 XiaoMi, Inc.
> > > + * Copyright (c) 2021 Caleb Connolly <caleb@connolly.tech>
> > > + * Copyright (c) 2023 Joel Selvaraj <joelselvaraj.oss@gmail.com>
> > > + */
> 
> [skip]
> 
> > > +static const struct of_device_id fts_of_match[] = {
> > > +	{ .compatible = "focaltech,fts5452", .data = &fts5452_chip_data },
> > > +	{ .compatible = "focaltech,fts8719", .data = &fts8719_chip_data },
> > > +	{ /* sentinel */ }
> > > +};
> > > +
> > > +MODULE_DEVICE_TABLE(of, fts_of_match);
> > > +
> > > +static struct i2c_driver fts_ts_driver = {
> > > +	.probe_new = fts_ts_probe,
> > > +	.id_table = fts_i2c_id,
> > > +	.driver = {
> > > +		.name = FTS_DRIVER_NAME,
> > > +		.pm = pm_sleep_ptr(&fts_dev_pm_ops),
> > > +		.of_match_table = fts_of_match,
> > > +	},
> > > +};
> > > +module_i2c_driver(fts_ts_driver);
> > > +
> > > +MODULE_AUTHOR("Joel Selvaraj <joelselvaraj.oss@gmail.com>");
> > > +MODULE_AUTHOR("Caleb Connolly <caleb@connolly.tech>");
> > > +MODULE_DESCRIPTION("Focaltech Touchscreen Driver");
> > 
> > Nit: mixing 'FocalTech' and 'Focaltech' throughout.
> > 
> > > +MODULE_LICENSE("GPL");
> > > -- 
> > > 2.40.0
> > > 
> > 
> > Kind regards,
> > Jeff LaBundy
> 
> Thank you,
> Joel Selvaraj

Kind regards,
Jeff LaBundy

^ permalink raw reply

* Re: [PATCH v5] Fix freeze in lm8333 i2c keyboard driver
From: Tomáš Mudruňka @ 2023-05-12 16:55 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Jeff LaBundy, linux-input, linux-kernel
In-Reply-To: <ZF19yOojiaSbo3vS@google.com>

> So this is still racy, isn't it? The interrupt may come after read is
> done, but before we register the handler.

Well. It is. But please see the rest of the thread, where we've
already discussed this.

Every time the interrupt handler runs, the interrupt is disabled and
then reenabled after i2c communication is done. Which means this exact
thing happens on each keypress anyway. So i don't think it's a
necessarily huge deal. It might not be perfect solution, but it makes
things much better. window in which the deadlock condition can happen
is now in range of few ms (or us), instead of ~10 seconds (previously
it included bootloader and basicaly any moment from power up to driver
load)

Another solution would be to trigger on LOW instead of FALLING as
proposed in initial version of the patch. That would be safer in terms
of lm8333 deadlock, but Jeff was concerned about possibility of
interrupt storm taking down whole system in case the IRQ line gets
stuck in LOW for some reason...

Tom

pá 12. 5. 2023 v 1:44 odesílatel Dmitry Torokhov
<dmitry.torokhov@gmail.com> napsal:
>
> On Wed, May 03, 2023 at 08:44:06PM -0500, Jeff LaBundy wrote:
> > Hi Tomas,
> >
> > On Wed, May 03, 2023 at 05:32:31PM +0200, Tomas Mudrunka wrote:
> > > LM8333 uses gpio interrupt line which is triggered by falling edge.
> > > When button is pressed before driver is loaded,
> > > driver will miss the edge and never respond again.
> > > To fix this we run the interrupt handler before registering IRQ
> > > to clear the interrupt via i2c command.
> > >
> > > Signed-off-by: Tomas Mudrunka <tomas.mudrunka@gmail.com>
> > > ---
> >
> > Reviewed-by: Jeff LaBundy <jeff@labundy.com>
> >
> > >  drivers/input/keyboard/lm8333.c | 2 ++
> > >  1 file changed, 2 insertions(+)
> > >
> > > diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
> > > index 7457c3220..52108c370 100644
> > > --- a/drivers/input/keyboard/lm8333.c
> > > +++ b/drivers/input/keyboard/lm8333.c
> > > @@ -178,6 +178,8 @@ static int lm8333_probe(struct i2c_client *client)
> > >                     dev_warn(&client->dev, "Unable to set active time\n");
> > >     }
> > >
> > > +   lm8333_irq_thread(client->irq, lm8333);
>
> So this is still racy, isn't it? The interrupt may come after read is
> done, but before we register the handler.
>
> > > +
> > >     err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
> > >                                IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> > >                                "lm8333", lm8333);
> > > --
> > > 2.40.1
> >
>
> Thanks.
>
> --
> Dmitry

^ permalink raw reply

* Re: [PATCH v5] Fix freeze in lm8333 i2c keyboard driver
From: Jeff LaBundy @ 2023-05-12 16:54 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Tomas Mudrunka, linux-input, linux-kernel
In-Reply-To: <ZF19yOojiaSbo3vS@google.com>

Hi Dmitry,

On Thu, May 11, 2023 at 04:44:08PM -0700, Dmitry Torokhov wrote:
> On Wed, May 03, 2023 at 08:44:06PM -0500, Jeff LaBundy wrote:
> > Hi Tomas,
> > 
> > On Wed, May 03, 2023 at 05:32:31PM +0200, Tomas Mudrunka wrote:
> > > LM8333 uses gpio interrupt line which is triggered by falling edge.
> > > When button is pressed before driver is loaded,
> > > driver will miss the edge and never respond again.
> > > To fix this we run the interrupt handler before registering IRQ
> > > to clear the interrupt via i2c command.
> > > 
> > > Signed-off-by: Tomas Mudrunka <tomas.mudrunka@gmail.com>
> > > ---
> > 
> > Reviewed-by: Jeff LaBundy <jeff@labundy.com>
> > 
> > >  drivers/input/keyboard/lm8333.c | 2 ++
> > >  1 file changed, 2 insertions(+)
> > > 
> > > diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
> > > index 7457c3220..52108c370 100644
> > > --- a/drivers/input/keyboard/lm8333.c
> > > +++ b/drivers/input/keyboard/lm8333.c
> > > @@ -178,6 +178,8 @@ static int lm8333_probe(struct i2c_client *client)
> > >  			dev_warn(&client->dev, "Unable to set active time\n");
> > >  	}
> > >  
> > > +	lm8333_irq_thread(client->irq, lm8333);
> 
> So this is still racy, isn't it? The interrupt may come after read is
> done, but before we register the handler.

You're absolutely correct; I had not considered this corner case. Apologies
for the churn Tomas.

In that case, it seems the solution is to either move the dummy read after
the handler is registered as in v4, or remove the hard-coded flag and allow
dts to specify level sensitivity.

> 
> > > +
> > >  	err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
> > >  				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> > >  				   "lm8333", lm8333);
> > > -- 
> > > 2.40.1
> > 
> 
> Thanks.
> 
> -- 
> Dmitry

Kind regards,
Jeff LaBundy

^ permalink raw reply

* [dtor-input:next] BUILD SUCCESS 17caa38a988e8f73e392f1f5ec2afb854552edcc
From: kernel test robot @ 2023-05-12  8:53 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
branch HEAD: 17caa38a988e8f73e392f1f5ec2afb854552edcc  dt-bindings: input: cypress,cyapa: convert to dtschema

elapsed time: 785m

configs tested: 181
configs skipped: 18

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                            allyesconfig   gcc  
alpha        buildonly-randconfig-r004-20230511   gcc  
alpha        buildonly-randconfig-r005-20230509   gcc  
alpha        buildonly-randconfig-r006-20230511   gcc  
alpha                               defconfig   gcc  
alpha                randconfig-r003-20230511   gcc  
alpha                randconfig-r005-20230509   gcc  
alpha                randconfig-r006-20230511   gcc  
alpha                randconfig-r026-20230511   gcc  
arc                              allyesconfig   gcc  
arc                                 defconfig   gcc  
arc                  randconfig-r005-20230511   gcc  
arc                  randconfig-r011-20230509   gcc  
arc                  randconfig-r014-20230509   gcc  
arc                  randconfig-r016-20230511   gcc  
arc                  randconfig-r024-20230511   gcc  
arc                  randconfig-r026-20230512   gcc  
arc                  randconfig-r031-20230509   gcc  
arc                  randconfig-r043-20230509   gcc  
arc                  randconfig-r043-20230511   gcc  
arm                              allmodconfig   gcc  
arm                              allyesconfig   gcc  
arm                       aspeed_g4_defconfig   clang
arm                                 defconfig   gcc  
arm                          exynos_defconfig   gcc  
arm                         orion5x_defconfig   clang
arm                  randconfig-r002-20230509   clang
arm                  randconfig-r024-20230509   gcc  
arm                  randconfig-r033-20230509   clang
arm                  randconfig-r046-20230509   gcc  
arm                  randconfig-r046-20230511   clang
arm64                            allyesconfig   gcc  
arm64        buildonly-randconfig-r002-20230511   clang
arm64                               defconfig   gcc  
arm64                randconfig-r003-20230509   gcc  
arm64                randconfig-r004-20230509   gcc  
arm64                randconfig-r014-20230511   gcc  
arm64                randconfig-r024-20230509   clang
arm64                randconfig-r032-20230511   clang
arm64                randconfig-r035-20230511   clang
csky                                defconfig   gcc  
csky                 randconfig-r004-20230511   gcc  
csky                 randconfig-r022-20230511   gcc  
csky                 randconfig-r025-20230511   gcc  
csky                 randconfig-r032-20230509   gcc  
hexagon              randconfig-r001-20230509   clang
hexagon              randconfig-r001-20230511   clang
hexagon              randconfig-r002-20230509   clang
hexagon              randconfig-r011-20230511   clang
hexagon              randconfig-r015-20230511   clang
hexagon              randconfig-r022-20230512   clang
hexagon              randconfig-r031-20230509   clang
hexagon              randconfig-r041-20230509   clang
hexagon              randconfig-r041-20230511   clang
hexagon              randconfig-r045-20230509   clang
hexagon              randconfig-r045-20230511   clang
i386                             allyesconfig   gcc  
i386                              debian-10.3   gcc  
i386                                defconfig   gcc  
ia64                             allmodconfig   gcc  
ia64                                defconfig   gcc  
ia64                 randconfig-r002-20230511   gcc  
ia64                 randconfig-r021-20230512   gcc  
ia64                 randconfig-r023-20230511   gcc  
ia64                 randconfig-r035-20230509   gcc  
loongarch                        allmodconfig   gcc  
loongarch                         allnoconfig   gcc  
loongarch                           defconfig   gcc  
loongarch            randconfig-r006-20230511   gcc  
loongarch            randconfig-r013-20230509   gcc  
loongarch            randconfig-r014-20230511   gcc  
loongarch            randconfig-r021-20230509   gcc  
loongarch            randconfig-r021-20230511   gcc  
loongarch            randconfig-r034-20230511   gcc  
m68k                             allmodconfig   gcc  
m68k         buildonly-randconfig-r003-20230509   gcc  
m68k                                defconfig   gcc  
m68k                       m5275evb_defconfig   gcc  
m68k                 randconfig-r012-20230511   gcc  
m68k                 randconfig-r014-20230509   gcc  
m68k                 randconfig-r025-20230512   gcc  
microblaze   buildonly-randconfig-r002-20230509   gcc  
microblaze           randconfig-r001-20230509   gcc  
microblaze           randconfig-r005-20230511   gcc  
microblaze           randconfig-r022-20230511   gcc  
microblaze           randconfig-r036-20230509   gcc  
mips                             allmodconfig   gcc  
mips                             allyesconfig   gcc  
mips         buildonly-randconfig-r001-20230509   clang
mips         buildonly-randconfig-r004-20230511   gcc  
mips                     decstation_defconfig   gcc  
mips                           ip22_defconfig   clang
mips                      pic32mzda_defconfig   clang
mips                 randconfig-r006-20230509   clang
mips                 randconfig-r011-20230511   clang
mips                 randconfig-r021-20230511   clang
mips                 randconfig-r023-20230511   clang
nios2                         10m50_defconfig   gcc  
nios2                               defconfig   gcc  
nios2                randconfig-r003-20230509   gcc  
nios2                randconfig-r023-20230512   gcc  
nios2                randconfig-r024-20230511   gcc  
nios2                randconfig-r024-20230512   gcc  
nios2                randconfig-r026-20230509   gcc  
nios2                randconfig-r036-20230509   gcc  
openrisc     buildonly-randconfig-r002-20230511   gcc  
openrisc     buildonly-randconfig-r006-20230511   gcc  
openrisc             randconfig-r002-20230511   gcc  
openrisc             randconfig-r025-20230509   gcc  
openrisc             randconfig-r026-20230509   gcc  
openrisc             randconfig-r031-20230511   gcc  
openrisc             randconfig-r033-20230511   gcc  
openrisc             randconfig-r035-20230511   gcc  
openrisc             randconfig-r036-20230511   gcc  
parisc                              defconfig   gcc  
parisc               randconfig-r013-20230511   gcc  
parisc               randconfig-r022-20230509   gcc  
parisc64                            defconfig   gcc  
powerpc                          allmodconfig   gcc  
powerpc                           allnoconfig   gcc  
powerpc      buildonly-randconfig-r001-20230511   gcc  
powerpc      buildonly-randconfig-r004-20230509   clang
powerpc                      cm5200_defconfig   gcc  
powerpc                    ge_imp3a_defconfig   clang
powerpc                     powernv_defconfig   clang
powerpc              randconfig-r005-20230509   gcc  
powerpc                 xes_mpc85xx_defconfig   clang
riscv                            alldefconfig   clang
riscv                            allmodconfig   gcc  
riscv                             allnoconfig   gcc  
riscv        buildonly-randconfig-r002-20230509   clang
riscv        buildonly-randconfig-r004-20230509   clang
riscv        buildonly-randconfig-r005-20230511   gcc  
riscv                               defconfig   gcc  
riscv                randconfig-r021-20230509   clang
riscv                randconfig-r022-20230509   clang
riscv                randconfig-r025-20230511   gcc  
riscv                randconfig-r034-20230509   gcc  
riscv                randconfig-r034-20230511   clang
riscv                randconfig-r042-20230509   clang
riscv                randconfig-r042-20230511   gcc  
riscv                          rv32_defconfig   gcc  
s390                             allmodconfig   gcc  
s390                             allyesconfig   gcc  
s390         buildonly-randconfig-r001-20230511   gcc  
s390                                defconfig   gcc  
s390                 randconfig-r013-20230509   clang
s390                 randconfig-r013-20230511   gcc  
s390                 randconfig-r023-20230509   clang
s390                 randconfig-r033-20230509   gcc  
s390                 randconfig-r033-20230511   clang
s390                 randconfig-r034-20230509   gcc  
s390                 randconfig-r044-20230509   clang
s390                 randconfig-r044-20230511   gcc  
sh                               allmodconfig   gcc  
sh                        apsh4ad0a_defconfig   gcc  
sh                   randconfig-r003-20230511   gcc  
sh                   randconfig-r004-20230511   gcc  
sh                   randconfig-r015-20230511   gcc  
sh                   sh7724_generic_defconfig   gcc  
sparc        buildonly-randconfig-r003-20230511   gcc  
sparc                               defconfig   gcc  
sparc                randconfig-r015-20230509   gcc  
sparc                randconfig-r016-20230509   gcc  
sparc64      buildonly-randconfig-r005-20230511   gcc  
sparc64              randconfig-r006-20230509   gcc  
sparc64              randconfig-r016-20230511   gcc  
sparc64              randconfig-r032-20230509   gcc  
sparc64              randconfig-r032-20230511   gcc  
um                             i386_defconfig   gcc  
um                           x86_64_defconfig   gcc  
x86_64                            allnoconfig   gcc  
x86_64                           allyesconfig   gcc  
x86_64                              defconfig   gcc  
x86_64                                  kexec   gcc  
x86_64                               rhel-8.3   gcc  
xtensa       buildonly-randconfig-r001-20230509   gcc  
xtensa       buildonly-randconfig-r006-20230509   gcc  
xtensa               randconfig-r001-20230511   gcc  
xtensa               randconfig-r004-20230509   gcc  
xtensa               randconfig-r035-20230509   gcc  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply

* Re: [PATCH 2/4] dt-bindings: touchscreen: add virtual-touchscreen and virtual-buttons properties
From: Michael Riesch @ 2023-05-12  8:13 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Javier Carrasco, Dmitry Torokhov,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bastian Hecht
  Cc: linux-kernel, linux-input, devicetree
In-Reply-To: <cdcd5656-2c7f-23bf-d016-fff79a279ebb@linaro.org>

Hi Krzysztof,

On 5/12/23 09:20, Krzysztof Kozlowski wrote:
> On 12/05/2023 09:08, Michael Riesch wrote:
>> Hi Krzysztof,
>>
>>>> These buttons are actually physical i.e. printed and with a given
>>>> functionality, but still part of the touchscreen as the physical device
>>>> is not aware of them. Therefore they only make sense in the touchscreen
>>>> context.
>>>
>>> So basically you still have the same touchscreen under the buttons and
>>> these are not separate devices. Whether someone put a sticker on
>>> touchscreen, does not really change hardware behavior and it's up to
>>> system to handle this. What you are trying to do here is to create
>>> virtual buttons through Devicetree and DT is not for that.
>>
>> I have already addressed a similar statement here:
>> https://lore.kernel.org/lkml/20230504042927.GA1129520@quokka/t/#m1a93595c36535312df0061459a1da5e062de6c44
>> but let me extend this comment a bit.
>>
>> The notion of "someone putting a sticker on touchscreen" does not really
>> reflect the use case we have in mind. We are talking about devices that
>> are shipped from the factory in a particular configuration, e.g.,
>>
>> +-----------------------+---------+
>> |                       |  power  |
>> |                       |  button |
>> |   touchscreen         +---------+
>> |   (behind: display)   |  return |
>> |                       |  button |
>> +-----------------------+---------+
>>
>> Here, the real touchscreen is larger than the display. The display is
>> behind the "touchscreen" part. Behind the buttons there are symbols
>> engraved in metal or printed foils or what not. I just would like to
>> make it clear that these symbols are not going to change.
>>
>> We believe that the engraved or printed symbols actually define the
>> (expected) hardware behavior. Of course there is a virtual notion to
>> that, and of course it would be possible to let the power button work as
>> return button and vice versa in software. However, the user sees the
>> engraved or printed symbols (which are not going to change) and expects
>> the device to react appropriately.
> 
> OK, I actually missed the concept that display is not equal to the
> touchscreen ("screen" actually suggests display :) ). In your case here
> it sounds good, but please put some parts of this description into this
> common binding. The sketch above is nice, especially if you can point
> where the virtual origin x/y are. Picture is thousands words.

I think this can be arranged :-)

>> Now if you suggest that the system (that is user space, right?) should
>> handle this, then the question would be which component is supposed to
>> handle the touchscreen events and react accordingly. I don't have an
>> answer to that and hope I don't need to find one. But independent of
>> that, a configuration file is required that defines the area of the
>> virtual buttons etc. Wouldn't this be similar to the (mostly) beloved
>> xorg.conf containing the definitions of input devices?
> 
> If the case was a bit different - e.g. display is everywhere - I could
> easily imagine that on the device rotation you want to move
> (re-position) the buttons. Or if user has some accessibility option
> enabled, you want bigger buttons. Then it would be a prove that it must
> be configured and managed from user-space. How, I don't know.

I fully agree here. If user space is able to draw the symbols, then
naturally it is also responsible for handling the events appropriately.
This could happen in an application with a GUI or on display
manager/compositor level (e.g., weston controller or similar).

But I take it that for the situation sketched above the device tree
approach is the correct one. Documentation should be improved, though.

Best regards,
Michael

^ permalink raw reply

* [dtor-input:for-linus] BUILD SUCCESS 7b63a88bb62ba2ddf5fcd956be85fe46624628b9
From: kernel test robot @ 2023-05-12  7:55 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git for-linus
branch HEAD: 7b63a88bb62ba2ddf5fcd956be85fe46624628b9  Input: psmouse - fix OOB access in Elantech protocol

elapsed time: 729m

configs tested: 132
configs skipped: 7

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                            allyesconfig   gcc  
alpha                               defconfig   gcc  
alpha                randconfig-r002-20230511   gcc  
alpha                randconfig-r006-20230511   gcc  
alpha                randconfig-r011-20230509   gcc  
arc                              allyesconfig   gcc  
arc                                 defconfig   gcc  
arc                  randconfig-r003-20230509   gcc  
arc                  randconfig-r023-20230509   gcc  
arc                  randconfig-r043-20230509   gcc  
arc                  randconfig-r043-20230511   gcc  
arm                              allmodconfig   gcc  
arm                              allyesconfig   gcc  
arm                                 defconfig   gcc  
arm                  randconfig-r016-20230509   gcc  
arm                  randconfig-r031-20230511   gcc  
arm                  randconfig-r033-20230509   clang
arm                  randconfig-r046-20230509   gcc  
arm                  randconfig-r046-20230511   clang
arm64                            allyesconfig   gcc  
arm64        buildonly-randconfig-r005-20230511   clang
arm64        buildonly-randconfig-r006-20230511   clang
arm64                               defconfig   gcc  
csky                                defconfig   gcc  
csky                 randconfig-r005-20230511   gcc  
hexagon              randconfig-r004-20230509   clang
hexagon              randconfig-r024-20230509   clang
hexagon              randconfig-r024-20230511   clang
hexagon              randconfig-r034-20230511   clang
hexagon              randconfig-r036-20230509   clang
hexagon              randconfig-r041-20230509   clang
hexagon              randconfig-r041-20230511   clang
hexagon              randconfig-r045-20230509   clang
hexagon              randconfig-r045-20230511   clang
i386                             allyesconfig   gcc  
i386                              debian-10.3   gcc  
i386                                defconfig   gcc  
i386                          randconfig-a001   gcc  
i386                          randconfig-a002   clang
i386                          randconfig-a003   gcc  
i386                          randconfig-a004   clang
i386                          randconfig-a005   gcc  
i386                          randconfig-a006   clang
i386                          randconfig-a011   clang
i386                          randconfig-a012   gcc  
i386                          randconfig-a013   clang
i386                          randconfig-a014   gcc  
i386                          randconfig-a015   clang
i386                          randconfig-a016   gcc  
ia64                             allmodconfig   gcc  
ia64         buildonly-randconfig-r005-20230509   gcc  
ia64                                defconfig   gcc  
ia64                 randconfig-r006-20230509   gcc  
ia64                 randconfig-r035-20230511   gcc  
loongarch                        allmodconfig   gcc  
loongarch                         allnoconfig   gcc  
loongarch                           defconfig   gcc  
loongarch            randconfig-r021-20230509   gcc  
loongarch            randconfig-r021-20230511   gcc  
m68k                             allmodconfig   gcc  
m68k         buildonly-randconfig-r003-20230511   gcc  
m68k                                defconfig   gcc  
m68k                 randconfig-r001-20230509   gcc  
m68k                 randconfig-r012-20230509   gcc  
m68k                 randconfig-r025-20230509   gcc  
m68k                 randconfig-r032-20230509   gcc  
microblaze   buildonly-randconfig-r001-20230511   gcc  
microblaze           randconfig-r013-20230509   gcc  
mips                             allmodconfig   gcc  
mips                             allyesconfig   gcc  
mips                 randconfig-r004-20230511   gcc  
mips                 randconfig-r011-20230511   clang
mips                 randconfig-r015-20230509   gcc  
nios2                               defconfig   gcc  
nios2                randconfig-r022-20230511   gcc  
nios2                randconfig-r033-20230511   gcc  
nios2                randconfig-r035-20230509   gcc  
parisc       buildonly-randconfig-r002-20230509   gcc  
parisc       buildonly-randconfig-r003-20230509   gcc  
parisc                              defconfig   gcc  
parisc               randconfig-r025-20230511   gcc  
parisc               randconfig-r026-20230511   gcc  
parisc64                            defconfig   gcc  
powerpc                          allmodconfig   gcc  
powerpc                           allnoconfig   gcc  
powerpc              randconfig-r003-20230511   clang
powerpc              randconfig-r005-20230509   gcc  
powerpc              randconfig-r034-20230509   gcc  
riscv                            allmodconfig   gcc  
riscv                             allnoconfig   gcc  
riscv                               defconfig   gcc  
riscv                randconfig-r026-20230509   clang
riscv                randconfig-r042-20230509   clang
riscv                randconfig-r042-20230511   gcc  
riscv                          rv32_defconfig   gcc  
s390                             allmodconfig   gcc  
s390                             allyesconfig   gcc  
s390                                defconfig   gcc  
s390                 randconfig-r013-20230509   clang
s390                 randconfig-r032-20230511   clang
s390                 randconfig-r044-20230509   clang
s390                 randconfig-r044-20230511   gcc  
sh                               allmodconfig   gcc  
sh                   randconfig-r014-20230509   gcc  
sh                   randconfig-r022-20230509   gcc  
sh                   randconfig-r023-20230511   gcc  
sparc        buildonly-randconfig-r004-20230509   gcc  
sparc        buildonly-randconfig-r006-20230509   gcc  
sparc                               defconfig   gcc  
sparc                randconfig-r002-20230509   gcc  
sparc                randconfig-r031-20230509   gcc  
sparc64      buildonly-randconfig-r002-20230511   gcc  
um                             i386_defconfig   gcc  
um                           x86_64_defconfig   gcc  
x86_64                            allnoconfig   gcc  
x86_64                           allyesconfig   gcc  
x86_64                              defconfig   gcc  
x86_64                                  kexec   gcc  
x86_64                        randconfig-a001   clang
x86_64                        randconfig-a002   gcc  
x86_64                        randconfig-a003   clang
x86_64                        randconfig-a004   gcc  
x86_64                        randconfig-a005   clang
x86_64                        randconfig-a006   gcc  
x86_64                        randconfig-a011   gcc  
x86_64                        randconfig-a012   clang
x86_64                        randconfig-a013   gcc  
x86_64                        randconfig-a014   clang
x86_64                        randconfig-a015   gcc  
x86_64                        randconfig-a016   clang
x86_64                               rhel-8.3   gcc  
xtensa       buildonly-randconfig-r004-20230511   gcc  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply

* Re: [PATCH 2/4] dt-bindings: touchscreen: add virtual-touchscreen and virtual-buttons properties
From: Krzysztof Kozlowski @ 2023-05-12  7:20 UTC (permalink / raw)
  To: Michael Riesch, Javier Carrasco, Dmitry Torokhov, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg, Bastian Hecht
  Cc: linux-kernel, linux-input, devicetree
In-Reply-To: <eb3f40e6-a604-39f2-eb49-8b41590a65d4@wolfvision.net>

On 12/05/2023 09:08, Michael Riesch wrote:
> Hi Krzysztof,
> 
>>> These buttons are actually physical i.e. printed and with a given
>>> functionality, but still part of the touchscreen as the physical device
>>> is not aware of them. Therefore they only make sense in the touchscreen
>>> context.
>>
>> So basically you still have the same touchscreen under the buttons and
>> these are not separate devices. Whether someone put a sticker on
>> touchscreen, does not really change hardware behavior and it's up to
>> system to handle this. What you are trying to do here is to create
>> virtual buttons through Devicetree and DT is not for that.
> 
> I have already addressed a similar statement here:
> https://lore.kernel.org/lkml/20230504042927.GA1129520@quokka/t/#m1a93595c36535312df0061459a1da5e062de6c44
> but let me extend this comment a bit.
> 
> The notion of "someone putting a sticker on touchscreen" does not really
> reflect the use case we have in mind. We are talking about devices that
> are shipped from the factory in a particular configuration, e.g.,
> 
> +-----------------------+---------+
> |                       |  power  |
> |                       |  button |
> |   touchscreen         +---------+
> |   (behind: display)   |  return |
> |                       |  button |
> +-----------------------+---------+
> 
> Here, the real touchscreen is larger than the display. The display is
> behind the "touchscreen" part. Behind the buttons there are symbols
> engraved in metal or printed foils or what not. I just would like to
> make it clear that these symbols are not going to change.
> 
> We believe that the engraved or printed symbols actually define the
> (expected) hardware behavior. Of course there is a virtual notion to
> that, and of course it would be possible to let the power button work as
> return button and vice versa in software. However, the user sees the
> engraved or printed symbols (which are not going to change) and expects
> the device to react appropriately.

OK, I actually missed the concept that display is not equal to the
touchscreen ("screen" actually suggests display :) ). In your case here
it sounds good, but please put some parts of this description into this
common binding. The sketch above is nice, especially if you can point
where the virtual origin x/y are. Picture is thousands words.

> 
> Now if you suggest that the system (that is user space, right?) should
> handle this, then the question would be which component is supposed to
> handle the touchscreen events and react accordingly. I don't have an
> answer to that and hope I don't need to find one. But independent of
> that, a configuration file is required that defines the area of the
> virtual buttons etc. Wouldn't this be similar to the (mostly) beloved
> xorg.conf containing the definitions of input devices?

If the case was a bit different - e.g. display is everywhere - I could
easily imagine that on the device rotation you want to move
(re-position) the buttons. Or if user has some accessibility option
enabled, you want bigger buttons. Then it would be a prove that it must
be configured and managed from user-space. How, I don't know.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH 2/4] dt-bindings: touchscreen: add virtual-touchscreen and virtual-buttons properties
From: Michael Riesch @ 2023-05-12  7:08 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Javier Carrasco, Dmitry Torokhov,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg,
	Bastian Hecht
  Cc: linux-kernel, linux-input, devicetree
In-Reply-To: <a7261bc1-902d-99f9-aa3e-2c90dd264c8d@linaro.org>

Hi Krzysztof,

On 5/12/23 08:25, Krzysztof Kozlowski wrote:
> On 11/05/2023 12:28, Javier Carrasco wrote:
>> On 11.05.23 11:45, Krzysztof Kozlowski wrote:
>>> On 10/05/2023 15:50, Javier Carrasco wrote:
>>>> The virtual-touchscreen object defines an area within the touchscreen
>>>> where touch events are reported and their coordinates get converted to
>>>> the virtual origin. This object avoids getting events from areas that
>>>> are physically hidden by overlay frames.
>>>>
>>>> For touchscreens where overlay buttons on the touchscreen surface are
>>>> provided, the virtual-buttons object contains a node for every button
>>>> and the key event that should be reported when pressed.
>>>
>>> Hm, I don't understand - are these separate physical buttons? If so, why
>>> would they be part of touchscreen? Where do the wires go?
>> Those buttons are actually printed on some overlays which are mounted on
>> top of the touchscreen and  they are used to provide a predefined
>> functionality to that touchscreen region. Any touchscreen with such a
>> physical overlay with buttons printed on them or clipped touchscreen
>> areas might use this functionality.
>>
>> These buttons are actually physical i.e. printed and with a given
>> functionality, but still part of the touchscreen as the physical device
>> is not aware of them. Therefore they only make sense in the touchscreen
>> context.
> 
> So basically you still have the same touchscreen under the buttons and
> these are not separate devices. Whether someone put a sticker on
> touchscreen, does not really change hardware behavior and it's up to
> system to handle this. What you are trying to do here is to create
> virtual buttons through Devicetree and DT is not for that.

I have already addressed a similar statement here:
https://lore.kernel.org/lkml/20230504042927.GA1129520@quokka/t/#m1a93595c36535312df0061459a1da5e062de6c44
but let me extend this comment a bit.

The notion of "someone putting a sticker on touchscreen" does not really
reflect the use case we have in mind. We are talking about devices that
are shipped from the factory in a particular configuration, e.g.,

+-----------------------+---------+
|                       |  power  |
|                       |  button |
|   touchscreen         +---------+
|   (behind: display)   |  return |
|                       |  button |
+-----------------------+---------+

Here, the real touchscreen is larger than the display. The display is
behind the "touchscreen" part. Behind the buttons there are symbols
engraved in metal or printed foils or what not. I just would like to
make it clear that these symbols are not going to change.

We believe that the engraved or printed symbols actually define the
(expected) hardware behavior. Of course there is a virtual notion to
that, and of course it would be possible to let the power button work as
return button and vice versa in software. However, the user sees the
engraved or printed symbols (which are not going to change) and expects
the device to react appropriately.

Now if you suggest that the system (that is user space, right?) should
handle this, then the question would be which component is supposed to
handle the touchscreen events and react accordingly. I don't have an
answer to that and hope I don't need to find one. But independent of
that, a configuration file is required that defines the area of the
virtual buttons etc. Wouldn't this be similar to the (mostly) beloved
xorg.conf containing the definitions of input devices?

Best regards,
Michael

^ permalink raw reply

* Re: [PATCH 2/4] dt-bindings: touchscreen: add virtual-touchscreen and virtual-buttons properties
From: Krzysztof Kozlowski @ 2023-05-12  6:25 UTC (permalink / raw)
  To: Javier Carrasco, Dmitry Torokhov, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Henrik Rydberg, Bastian Hecht,
	Michael Riesch
  Cc: linux-kernel, linux-input, devicetree
In-Reply-To: <18526d2a-ac5f-2b26-9ed3-5a82f20cac86@wolfvision.net>

On 11/05/2023 12:28, Javier Carrasco wrote:
> On 11.05.23 11:45, Krzysztof Kozlowski wrote:
>> On 10/05/2023 15:50, Javier Carrasco wrote:
>>> The virtual-touchscreen object defines an area within the touchscreen
>>> where touch events are reported and their coordinates get converted to
>>> the virtual origin. This object avoids getting events from areas that
>>> are physically hidden by overlay frames.
>>>
>>> For touchscreens where overlay buttons on the touchscreen surface are
>>> provided, the virtual-buttons object contains a node for every button
>>> and the key event that should be reported when pressed.
>>
>> Hm, I don't understand - are these separate physical buttons? If so, why
>> would they be part of touchscreen? Where do the wires go?
> Those buttons are actually printed on some overlays which are mounted on
> top of the touchscreen and  they are used to provide a predefined
> functionality to that touchscreen region. Any touchscreen with such a
> physical overlay with buttons printed on them or clipped touchscreen
> areas might use this functionality.
> 
> These buttons are actually physical i.e. printed and with a given
> functionality, but still part of the touchscreen as the physical device
> is not aware of them. Therefore they only make sense in the touchscreen
> context.

So basically you still have the same touchscreen under the buttons and
these are not separate devices. Whether someone put a sticker on
touchscreen, does not really change hardware behavior and it's up to
system to handle this. What you are trying to do here is to create
virtual buttons through Devicetree and DT is not for that.

Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH 6/7] Input: libps2 - introduce common interrupt handler
From: kernel test robot @ 2023-05-12  1:01 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input
  Cc: llvm, oe-kbuild-all, Raul E Rangel, linux-kernel
In-Reply-To: <20230511185252.386941-7-dmitry.torokhov@gmail.com>

Hi Dmitry,

kernel test robot noticed the following build errors:

[auto build test ERROR on dtor-input/next]
[also build test ERROR on dtor-input/for-linus hid/for-next linus/master v6.4-rc1 next-20230511]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Dmitry-Torokhov/Input-libps2-attach-ps2dev-instances-as-serio-port-s-drvdata/20230512-025431
base:   https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
patch link:    https://lore.kernel.org/r/20230511185252.386941-7-dmitry.torokhov%40gmail.com
patch subject: [PATCH 6/7] Input: libps2 - introduce common interrupt handler
config: mips-randconfig-r031-20230510 (https://download.01.org/0day-ci/archive/20230512/202305120818.unCn8fQ9-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project b0fb98227c90adf2536c9ad644a74d5e92961111)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install mips cross compiling tool for clang build
        # apt-get install binutils-mipsel-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/1f2ba3a941e6f6a3ad745fa780825ac56570616e
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Dmitry-Torokhov/Input-libps2-attach-ps2dev-instances-as-serio-port-s-drvdata/20230512-025431
        git checkout 1f2ba3a941e6f6a3ad745fa780825ac56570616e
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=mips olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=mips SHELL=/bin/bash drivers/input/keyboard/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202305120818.unCn8fQ9-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/input/keyboard/atkbd.c:424:3: error: must use 'struct' tag to refer to type 'atkbd'
                   atkbd->resend = false;
                   ^
                   struct 
>> drivers/input/keyboard/atkbd.c:424:3: error: expected expression
   2 errors generated.


vim +424 drivers/input/keyboard/atkbd.c

^1da177e4c3f41 Linus Torvalds  2005-04-16  400  
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  401  static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev,
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  402  						   u8 data, unsigned int flags)
^1da177e4c3f41 Linus Torvalds  2005-04-16  403  {
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  404  	struct serio *serio = ps2dev->serio;
^1da177e4c3f41 Linus Torvalds  2005-04-16  405  
a9a1f9c315c27f Dmitry Torokhov 2010-01-06  406  	dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
^1da177e4c3f41 Linus Torvalds  2005-04-16  407  
^1da177e4c3f41 Linus Torvalds  2005-04-16  408  #if !defined(__i386__) && !defined (__x86_64__)
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  409  	if ((flags & (SERIO_FRAME | SERIO_PARITY)) &&
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  410  	    (~flags & SERIO_TIMEOUT)) {
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  411  		struct atkbd *atkbd = container_of(ps2dev, struct atkbd,
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  412  						   ps2dev);
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  413  
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  414  		if (!atkbd->resend && atkbd->write) {
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  415  			dev_warn(&serio->dev,
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  416  				 "Frame/parity error: %02x\n", flags);
^1da177e4c3f41 Linus Torvalds  2005-04-16  417  			serio_write(serio, ATKBD_CMD_RESEND);
a9a1f9c315c27f Dmitry Torokhov 2010-01-06  418  			atkbd->resend = true;
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  419  			return PS2_IGNORE;
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  420  		}
^1da177e4c3f41 Linus Torvalds  2005-04-16  421  	}
^1da177e4c3f41 Linus Torvalds  2005-04-16  422  
^1da177e4c3f41 Linus Torvalds  2005-04-16  423  	if (!flags && data == ATKBD_RET_ACK)
a9a1f9c315c27f Dmitry Torokhov 2010-01-06 @424  		atkbd->resend = false;
^1da177e4c3f41 Linus Torvalds  2005-04-16  425  #endif
^1da177e4c3f41 Linus Torvalds  2005-04-16  426  
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  427  	return PS2_PROCESS;
1f2ba3a941e6f6 Dmitry Torokhov 2023-05-11  428  }
^1da177e4c3f41 Linus Torvalds  2005-04-16  429  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply

* Re: [PATCH v3 2/5] Input: add driver for Focaltech FTS touchscreen
From: Joel Selvaraj @ 2023-05-12  0:43 UTC (permalink / raw)
  To: Jeff LaBundy
  Cc: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Markuss Broks, Jean Delvare,
	Max Krummenacher, Chris Morgan, Job Noorman, Alistair Francis,
	Hans de Goede, Maxime Ripard, linux-input, devicetree,
	linux-kernel, linux-arm-msm, ~postmarketos/upstreaming,
	phone-devel
In-Reply-To: <ZEXr1hC+Q5Bo/3Tc@nixie71>

Hi Jeff LaBundy,

On 4/23/23 21:39, Jeff LaBundy wrote:
> Hi Joel,
> 
> Great work so far! It's coming along nicely. Please find my latest
> feedback below.

Sorry for the late reply, university semester end got me hooked up.
I have a sad kind of good news... As pointed out by Hans de Goede, the 
edt-ft5x06 driver works out of the box for the fts8719 touchscreen in my 
device. So I think this patch series is no longer needed. I did have a 
look at the driver once when working on this patch series, but it looked 
different/not compatible at that time. After mentioned by Hans de Goede, 
I had a more closer look and the main touch buffer handling seems to be 
the same.

I am sorry as we put some considerable time in this patch series. I 
should have noted more carefully. Thank you though as I learnt things 
working on this patch series.

I guess I will send a different patch to add the compatible data to the 
existing edt-ft5x06 driver and dts changes to include that driver to my 
device.

> On Fri, Apr 14, 2023 at 09:02:19PM -0500, Joel Selvaraj wrote:
>> The Focaltech FTS driver supports several variants of focaltech
>> touchscreens found in ~2018 era smartphones including variants found on
>> the PocoPhone F1 and the SHIFT6mq which are already present in mainline.
>> This driver is loosely based on the original driver from Focaltech
>> but has been simplified and largely reworked.
>>
>> Co-developed-by: Caleb Connolly <caleb@connolly.tech>
>> Signed-off-by: Caleb Connolly <caleb@connolly.tech>
>> Signed-off-by: Joel Selvaraj <joelselvaraj.oss@gmail.com>
>> ---
>>   MAINTAINERS                                   |   8 +
>>   drivers/input/touchscreen/Kconfig             |  12 +
>>   drivers/input/touchscreen/Makefile            |   1 +
>>   drivers/input/touchscreen/focaltech_fts5452.c | 432 ++++++++++++++++++
>>   4 files changed, 453 insertions(+)
>>   create mode 100644 drivers/input/touchscreen/focaltech_fts5452.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 7ec4ce64f66d..1a3ea61e1f52 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -8028,6 +8028,14 @@ L:	linux-input@vger.kernel.org
>>   S:	Maintained
>>   F:	drivers/input/joystick/fsia6b.c
>>   
>> +FOCALTECH FTS5452 TOUCHSCREEN DRIVER
>> +M:	Joel Selvaraj <joelselvaraj.oss@gmail.com>
>> +M:	Caleb Connolly <caleb@connolly.tech>
>> +L:	linux-input@vger.kernel.org
>> +S:	Maintained
>> +F:	Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml
>> +F:	drivers/input/touchscreen/focaltech_fts5452.c
>> +
>>   FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER
>>   M:	Geoffrey D. Bennett <g@b4.vu>
>>   L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
>> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>> index 1feecd7ed3cb..11af91504969 100644
>> --- a/drivers/input/touchscreen/Kconfig
>> +++ b/drivers/input/touchscreen/Kconfig
>> @@ -388,6 +388,18 @@ config TOUCHSCREEN_EXC3000
>>   	  To compile this driver as a module, choose M here: the
>>   	  module will be called exc3000.
>>   
>> +config TOUCHSCREEN_FOCALTECH_FTS5452
>> +	tristate "Focaltech FTS Touchscreen"
>> +	depends on I2C
>> +	help
>> +	  Say Y here to enable support for I2C connected Focaltech FTS
>> +	  based touch panels, including the 5452 and 8917 panels.
> 
> This language is a bit misleading, as it seems to suggest three or more
> models are supported. It seems the title should simply be "FocalTech
> FTS5452 touchscreen controller" with the description as "...FocalTech
> FTS5452 and compatible touchscreen controllers."
> 
> As more are found to be compatible (e.g. FTS8917), the compatible strings
> can simply be appended.
> 
>> +
>> +	  If unsure, say N.
>> +
>> +	  To compile this driver as a module, choose M here: the
>> +	  module will be called focaltech_fts.
>> +
>>   config TOUCHSCREEN_FUJITSU
>>   	tristate "Fujitsu serial touchscreen"
>>   	select SERIO
>> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
>> index 159cd5136fdb..47d78c9cff21 100644
>> --- a/drivers/input/touchscreen/Makefile
>> +++ b/drivers/input/touchscreen/Makefile
>> @@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
>>   obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
>>   obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)	+= egalax_ts_serial.o
>>   obj-$(CONFIG_TOUCHSCREEN_EXC3000)	+= exc3000.o
>> +obj-$(CONFIG_TOUCHSCREEN_FOCALTECH_FTS5452)	+= focaltech_fts5452.o
>>   obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
>>   obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix_ts.o
>>   obj-$(CONFIG_TOUCHSCREEN_HIDEEP)	+= hideep.o
>> diff --git a/drivers/input/touchscreen/focaltech_fts5452.c b/drivers/input/touchscreen/focaltech_fts5452.c
>> new file mode 100644
>> index 000000000000..abf8a2f271ca
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/focaltech_fts5452.c
>> @@ -0,0 +1,432 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * FocalTech touchscreen driver.
>> + *
>> + * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved.
>> + * Copyright (C) 2018 XiaoMi, Inc.
>> + * Copyright (c) 2021 Caleb Connolly <caleb@connolly.tech>
>> + * Copyright (c) 2023 Joel Selvaraj <joelselvaraj.oss@gmail.com>
>> + */

[skip]

>> +static const struct of_device_id fts_of_match[] = {
>> +	{ .compatible = "focaltech,fts5452", .data = &fts5452_chip_data },
>> +	{ .compatible = "focaltech,fts8719", .data = &fts8719_chip_data },
>> +	{ /* sentinel */ }
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, fts_of_match);
>> +
>> +static struct i2c_driver fts_ts_driver = {
>> +	.probe_new = fts_ts_probe,
>> +	.id_table = fts_i2c_id,
>> +	.driver = {
>> +		.name = FTS_DRIVER_NAME,
>> +		.pm = pm_sleep_ptr(&fts_dev_pm_ops),
>> +		.of_match_table = fts_of_match,
>> +	},
>> +};
>> +module_i2c_driver(fts_ts_driver);
>> +
>> +MODULE_AUTHOR("Joel Selvaraj <joelselvaraj.oss@gmail.com>");
>> +MODULE_AUTHOR("Caleb Connolly <caleb@connolly.tech>");
>> +MODULE_DESCRIPTION("Focaltech Touchscreen Driver");
> 
> Nit: mixing 'FocalTech' and 'Focaltech' throughout.
> 
>> +MODULE_LICENSE("GPL");
>> -- 
>> 2.40.0
>>
> 
> Kind regards,
> Jeff LaBundy

Thank you,
Joel Selvaraj

^ permalink raw reply

* Re: [PATCH] Input: elan_i2c - Implement inhibit/uninhibit functions.
From: 'Dmitry Torokhov' @ 2023-05-12  0:07 UTC (permalink / raw)
  To: Jingle.Wu; +Cc: linux-kernel, linux-input, phoenix, josh.chen, dave.wang
In-Reply-To: <000b01d97978$32775ca0$976615e0$@emc.com.tw>

Hi Jingle,

On Fri, Apr 28, 2023 at 10:21:53AM +0800, Jingle.Wu wrote:
> Hi Dmitry:
> 	During the initial process and when the users open/close device,
> having the elan uninhibit/inhibit commands (low power mode) was not what
> Elan expects to happen. Due to that touchpad would do the calibration in
> uninhibit moment , we don't want the calibration to be affected by fingers
> on the touchpad.
> 	However, the LID inhibit/uninhibit functions in the Linux kernel
> driver calls open/close(), so we need to separate the inhibit/uninhibit
> behavior from open/close() function
> 	
> https://elixir.bootlin.com/linux/latest/source/drivers/input/input.c#L1783
> 	
> https://elixir.bootlin.com/linux/latest/source/drivers/input/input.c#L1813

You quite intentionally can not separate inhibit/uninhibit from open and
close. As with open/close nothing stops inhibit/uninhibit to be called
rapidly multiple times in a row. You probably rely on particular
operation of ChromeOS devices during normal user interaction.

As far as I remember, you need to perform recalibration on certain
devices when LID gets open. I recommend you implement something similar
to https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/3578852
where we monitor LID events and recalibrate when needed, instead of
trying to make assumptions on when inhibit and uninhibit functions are
called.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH 2/2] Input: cap11xx - add advanced sensitivity settings
From: Dmitry Torokhov @ 2023-05-11 23:57 UTC (permalink / raw)
  To: Jiri Valek - 2N
  Cc: krzysztof.kozlowski+dt, devicetree, linux-input, linux-kernel,
	robh+dt, u.kleine-koenig
In-Reply-To: <20230414233815.4004526-3-jiriv@axis.com>

Hi Jiri,

On Sat, Apr 15, 2023 at 01:38:15AM +0200, Jiri Valek - 2N wrote:
> @@ -474,7 +645,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
>  	if (error)
>  		return error;
>  
> -	irq = irq_of_parse_and_map(node, 0);
> +	irq = irq_of_parse_and_map(dev->of_node, 0);

Do you know if this is actually needed or we can rely on I2C core to
figure out the interrupt for us?

Also, could I ask you to move the driver from of_property_*() to
device_property_*() API?

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v5] Fix freeze in lm8333 i2c keyboard driver
From: Dmitry Torokhov @ 2023-05-11 23:44 UTC (permalink / raw)
  To: Jeff LaBundy; +Cc: Tomas Mudrunka, linux-input, linux-kernel
In-Reply-To: <ZFMN5nmqLAX170SE@nixie71>

On Wed, May 03, 2023 at 08:44:06PM -0500, Jeff LaBundy wrote:
> Hi Tomas,
> 
> On Wed, May 03, 2023 at 05:32:31PM +0200, Tomas Mudrunka wrote:
> > LM8333 uses gpio interrupt line which is triggered by falling edge.
> > When button is pressed before driver is loaded,
> > driver will miss the edge and never respond again.
> > To fix this we run the interrupt handler before registering IRQ
> > to clear the interrupt via i2c command.
> > 
> > Signed-off-by: Tomas Mudrunka <tomas.mudrunka@gmail.com>
> > ---
> 
> Reviewed-by: Jeff LaBundy <jeff@labundy.com>
> 
> >  drivers/input/keyboard/lm8333.c | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
> > index 7457c3220..52108c370 100644
> > --- a/drivers/input/keyboard/lm8333.c
> > +++ b/drivers/input/keyboard/lm8333.c
> > @@ -178,6 +178,8 @@ static int lm8333_probe(struct i2c_client *client)
> >  			dev_warn(&client->dev, "Unable to set active time\n");
> >  	}
> >  
> > +	lm8333_irq_thread(client->irq, lm8333);

So this is still racy, isn't it? The interrupt may come after read is
done, but before we register the handler.

> > +
> >  	err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
> >  				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> >  				   "lm8333", lm8333);
> > -- 
> > 2.40.1
> 

Thanks.

-- 
Dmitry

^ permalink raw reply

* [BUG: 6.3 kernel] Logitech Trackball M575 misidentified
From: Xose Vazquez Perez @ 2023-05-11 21:22 UTC (permalink / raw)
  To: linux-input

Hi,

6.3.2 kernel identifies "Logitech" "ERGO M575" as "Logitech" "(\xc9_O\x04)",
6.2.15 works fine.


6.2.15 boot log:
input: Logitech ERGO M575 as /devices/pci0000:00/0000:00:1a.0/usb3/3-1/3-1.3/3-1.3:1.2/0003:046D:C52B.0003/0003:046D:4096.0005/input/input15
logitech-hidpp-device 0003:046D:4096.0005: input,hidraw1: USB HID v1.11 Mouse [Logitech ERGO M575] on usb-0000:00:1a.0-1.3/input2:1

6.3.2 boot log:
input: Logitech \xc9_O\x04 as /devices/pci0000:00/0000:00:1a.0/usb3/3-1/3-1.3/3-1.3:1.2/0003:046D:C52B.0003/0003:046D:4096.0005/input/input15
logitech-hidpp-device 0003:046D:4096.0005: input,hidraw2: USB HID v1.11 Mouse [Logitech \xc9_O\x04] on usb-0000:00:1a.0-1.3/input2:1


Thanks.

^ permalink raw reply

* Re: [PATCH v4 1/2] dt-bindings: gpio: Convert STMPE GPIO to YAML schema
From: Linus Walleij @ 2023-05-11 20:39 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Rob Herring, Krzysztof Kozlowski, Maxime Coquelin,
	Alexandre Torgue, Dmitry Torokhov, Lee Jones, Philippe Schenker,
	Stefan Agner, Marek Vasut, Steffen Trumtrar, linux-gpio,
	devicetree, linux-stm32, linux-arm-kernel, linux-kernel,
	linux-input
In-Reply-To: <CAMRc=MdsBiV3AvzSPtCuR58w0N9z7o+hUrBDtXUC4a++pECb8w@mail.gmail.com>

On Thu, May 11, 2023 at 4:58 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> Applied, thanks!

That works ... but patch 2/2 depends on this one. (uses $ref).
You'd have to give Lee an immutable branch that he can pull
before applying patch 2/2 so he has the dependency, or let him
apply both.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH] selftests: hid: Add touch tests for Wacom devices
From: Joshua Dickens @ 2023-05-11 19:47 UTC (permalink / raw)
  To: linux-input, Jiri Kosina, Benjamin Tissoires
  Cc: Ping Cheng, Aaron Armstrong Skomra, Jason Gerecke, Joshua Dickens,
	Joshua Dickens, Jason Gerecke

Adding a wacom touch device to use the test_multitouch tests.
Adding a 2 additional tests.
 - A test to check if a touch event is sent when the contact_id of the event is 0.
 - A test to check if a touch event is not sent when confidence is set to 0.

Signed-off-by: Joshua Dickens <joshua.dickens@wacom.com>
Reviewed-by: Jason Gerecke <jason.gerecke@wacom.com>
---
 .../selftests/hid/tests/test_wacom_generic.py | 84 ++++++++++++++++++-
 1 file changed, 81 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py
index b1eb2bc787fc..f92fe8e02c1b 100644
--- a/tools/testing/selftests/hid/tests/test_wacom_generic.py
+++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py
@@ -31,6 +31,7 @@ from enum import Enum
 from hidtools.hut import HUT
 from hidtools.hid import HidUnit
 from . import base
+from . import test_multitouch
 import libevdev
 import pytest
 
@@ -517,7 +518,7 @@ class BaseTest:
                 for usage in get_report_usages(report):
                     yield usage
 
-        def assertName(self, uhdev):
+        def assertName(self, uhdev, type):
             """
             Assert that the name is as we expect.
 
@@ -526,7 +527,7 @@ class BaseTest:
             this assertion from the base class to work properly.
             """
             evdev = uhdev.get_evdev()
-            expected_name = uhdev.name + " Pen"
+            expected_name = uhdev.name + type
             if "wacom" not in expected_name.lower():
                 expected_name = "Wacom " + expected_name
             assert evdev.name == expected_name
@@ -549,6 +550,12 @@ class BaseTest:
                 usage_id("Generic Desktop", "Y"): PhysRange(
                     PhysRange.CENTIMETER, 5, 150
                 ),
+                usage_id("Digitizers", "Width"): PhysRange(
+                    PhysRange.CENTIMETER, 5, 150
+                ),
+                usage_id("Digitizers", "Height"): PhysRange(
+                    PhysRange.CENTIMETER, 5, 150
+                ),
                 usage_id("Digitizers", "X Tilt"): PhysRange(PhysRange.DEGREE, 90, 180),
                 usage_id("Digitizers", "Y Tilt"): PhysRange(PhysRange.DEGREE, 90, 180),
                 usage_id("Digitizers", "Twist"): PhysRange(PhysRange.DEGREE, 358, 360),
@@ -603,7 +610,17 @@ class BaseTest:
             pass
 
 
-class TestOpaqueTablet(BaseTest.TestTablet):
+class PenTabletTest(BaseTest.TestTablet):
+    def assertName(self, uhdev):
+        super().assertName(uhdev, " Pen")
+
+
+class TouchTabletTest(BaseTest.TestTablet):
+    def assertName(self, uhdev):
+        super().assertName(uhdev, " Finger")
+
+
+class TestOpaqueTablet(PenTabletTest):
     def create_device(self):
         return OpaqueTablet()
 
@@ -842,3 +859,64 @@ class TestPTHX60_Pen(TestOpaqueCTLTablet):
                 libevdev.InputEvent(libevdev.EV_KEY.BTN_0, 0),
             ],
         )
+
+
+class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest):
+    def create_device(self):
+        return test_multitouch.Digitizer(
+            "DTH 2452",
+            rdesc="05 0d 09 04 a1 01 85 0c 95 01 75 08 15 00 26 ff 00 81 03 09 54 81 02 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 09 22 a1 02 05 0d 95 01 75 01 25 01 09 42 81 02 81 03 09 47 81 02 95 05 81 03 09 51 26 ff 00 75 10 95 01 81 02 35 00 65 11 55 0e 05 01 09 30 26 a0 44 46 96 14 81 42 09 31 26 9a 26 46 95 0b 81 42 05 0d 75 08 95 01 15 00 09 48 26 5f 00 46 7c 14 81 02 09 49 25 35 46 7d 0b 81 02 45 00 65 00 55 00 c0 05 0d 27 ff ff 00 00 75 10 95 01 09 56 81 02 75 08 95 0e 81 03 09 55 26 ff 00 75 08 b1 02 85 0a 06 00 ff 09 c5 96 00 01 b1 02 c0 06 00 ff 09 01 a1 01 09 01 85 13 15 00 26 ff 00 75 08 95 3f 81 02 06 00 ff 09 01 15 00 26 ff 00 75 08 95 3f 91 02 c0",
+            input_info=(0x3, 0x056A, 0x0383),
+        )
+
+    def test_contact_id_0(self):
+        """
+        Bring a finger in contact with the tablet, then hold it down and remove it.
+
+        Ensure that even with contact ID = 0 which is usually given as an invalid
+        touch event by most tablets with the exception of a few, that given the
+        confidence bit is set to 1 it should process it as a valid touch to cover
+        the few tablets using contact ID = 0 as a valid touch value.
+        """
+        uhdev = self.uhdev
+        evdev = uhdev.get_evdev()
+
+        t0 = test_multitouch.Touch(0, 50, 100)
+        r = uhdev.event([t0])
+        events = uhdev.next_sync_events()
+        self.debug_reports(r, uhdev, events)
+
+        slot = self.get_slot(uhdev, t0, 0)
+
+        assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
+        assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
+        assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
+        assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
+
+        t0.tipswitch = False
+        if uhdev.quirks is None or "VALID_IS_INRANGE" not in uhdev.quirks:
+            t0.inrange = False
+        r = uhdev.event([t0])
+        events = uhdev.next_sync_events()
+        self.debug_reports(r, uhdev, events)
+        assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
+        assert evdev.slots[slot][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
+
+    def test_confidence_false(self):
+        """
+        Bring a finger in contact with the tablet with confidence set to false.
+
+        Ensure that the confidence bit being set to false should not result in a touch event.
+        """
+        uhdev = self.uhdev
+        evdev = uhdev.get_evdev()
+
+        t0 = test_multitouch.Touch(1, 50, 100)
+        t0.confidence = False
+        r = uhdev.event([t0])
+        events = uhdev.next_sync_events()
+        self.debug_reports(r, uhdev, events)
+
+        slot = self.get_slot(uhdev, t0, 0)
+
+        assert not events
\ No newline at end of file
-- 
2.40.0


^ permalink raw reply related

* [PATCH 6/7] Input: libps2 - introduce common interrupt handler
From: Dmitry Torokhov @ 2023-05-11 18:52 UTC (permalink / raw)
  To: linux-input; +Cc: Raul E Rangel, linux-kernel
In-Reply-To: <20230511185252.386941-1-dmitry.torokhov@gmail.com>

Instead of exposing inner workings of libps2 to drivers such as atkbd and
psmouse, have them define pre-receive and receive callbacks, and provide a
common handler that can be used with underlying serio port.

While at this add kerneldoc to the module.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/keyboard/atkbd.c     |  73 +++++-----
 drivers/input/mouse/psmouse-base.c |  53 +++----
 drivers/input/serio/libps2.c       | 226 ++++++++++++++++++++---------
 include/linux/libps2.h             |  61 +++++---
 4 files changed, 259 insertions(+), 154 deletions(-)

diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 2fb2ad73e796..8ef663a589b3 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -398,47 +398,49 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code
 	return code;
 }
 
-/*
- * atkbd_interrupt(). Here takes place processing of data received from
- * the keyboard into events.
- */
-
-static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
-				   unsigned int flags)
+static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev,
+						   u8 data, unsigned int flags)
 {
-	struct atkbd *atkbd = atkbd_from_serio(serio);
-	struct input_dev *dev = atkbd->dev;
-	unsigned int code = data;
-	int scroll = 0, hscroll = 0, click = -1;
-	int value;
-	unsigned short keycode;
+	struct serio *serio = ps2dev->serio;
 
 	dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
 
 #if !defined(__i386__) && !defined (__x86_64__)
-	if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
-		dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags);
-		serio_write(serio, ATKBD_CMD_RESEND);
-		atkbd->resend = true;
-		goto out;
+	if ((flags & (SERIO_FRAME | SERIO_PARITY)) &&
+	    (~flags & SERIO_TIMEOUT)) {
+		struct atkbd *atkbd = container_of(ps2dev, struct atkbd,
+						   ps2dev);
+
+		if (!atkbd->resend && atkbd->write) {
+			dev_warn(&serio->dev,
+				 "Frame/parity error: %02x\n", flags);
+			serio_write(serio, ATKBD_CMD_RESEND);
+			atkbd->resend = true;
+			return PS2_IGNORE;
+		}
 	}
 
 	if (!flags && data == ATKBD_RET_ACK)
 		atkbd->resend = false;
 #endif
 
-	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
-		if  (ps2_handle_ack(&atkbd->ps2dev, data))
-			goto out;
+	return PS2_PROCESS;
+}
 
-	if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
-		if  (ps2_handle_response(&atkbd->ps2dev, data))
-			goto out;
+static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data)
+{
+	struct serio *serio = ps2dev->serio;
+	struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev);
+	struct input_dev *dev = atkbd->dev;
+	unsigned int code = data;
+	int scroll = 0, hscroll = 0, click = -1;
+	int value;
+	unsigned short keycode;
 
 	pm_wakeup_event(&serio->dev, 0);
 
 	if (!atkbd->enabled)
-		goto out;
+		return;
 
 	input_event(dev, EV_MSC, MSC_RAW, code);
 
@@ -460,16 +462,16 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
 	case ATKBD_RET_BAT:
 		atkbd->enabled = false;
 		serio_reconnect(atkbd->ps2dev.serio);
-		goto out;
+		return;
 	case ATKBD_RET_EMUL0:
 		atkbd->emul = 1;
-		goto out;
+		return;
 	case ATKBD_RET_EMUL1:
 		atkbd->emul = 2;
-		goto out;
+		return;
 	case ATKBD_RET_RELEASE:
 		atkbd->release = true;
-		goto out;
+		return;
 	case ATKBD_RET_ACK:
 	case ATKBD_RET_NAK:
 		if (printk_ratelimit())
@@ -477,18 +479,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
 				 "Spurious %s on %s. "
 				 "Some program might be trying to access hardware directly.\n",
 				 data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
-		goto out;
+		return;
 	case ATKBD_RET_ERR:
 		atkbd->err_count++;
 		dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
 			serio->phys);
-		goto out;
+		return;
 	}
 
 	code = atkbd_compat_scancode(atkbd, code);
 
 	if (atkbd->emul && --atkbd->emul)
-		goto out;
+		return;
 
 	keycode = atkbd->keycode[code];
 
@@ -564,8 +566,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
 	}
 
 	atkbd->release = false;
-out:
-	return IRQ_HANDLED;
 }
 
 static int atkbd_set_repeat_rate(struct atkbd *atkbd)
@@ -1229,7 +1229,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 		goto fail1;
 
 	atkbd->dev = dev;
-	ps2_init(&atkbd->ps2dev, serio);
+	ps2_init(&atkbd->ps2dev, serio,
+		 atkbd_pre_receive_byte, atkbd_receive_byte);
 	INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work);
 	mutex_init(&atkbd->mutex);
 
@@ -1385,7 +1386,7 @@ static struct serio_driver atkbd_drv = {
 	},
 	.description	= DRIVER_DESC,
 	.id_table	= atkbd_serio_ids,
-	.interrupt	= atkbd_interrupt,
+	.interrupt	= ps2_interrupt,
 	.connect	= atkbd_connect,
 	.reconnect	= atkbd_reconnect,
 	.disconnect	= atkbd_disconnect,
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index ed5376099fba..a0aac76b1e41 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -336,17 +336,14 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data)
 	}
 }
 
-/*
- * psmouse_interrupt() handles incoming characters, either passing them
- * for normal processing or gathering them as command response.
- */
-static irqreturn_t psmouse_interrupt(struct serio *serio,
-				     u8 data, unsigned int flags)
+static enum ps2_disposition psmouse_pre_receive_byte(struct ps2dev *ps2dev,
+						     u8 data,
+						     unsigned int flags)
 {
-	struct psmouse *psmouse = psmouse_from_serio(serio);
+	struct psmouse *psmouse = container_of(ps2dev, struct psmouse, ps2dev);
 
 	if (psmouse->state == PSMOUSE_IGNORE)
-		goto out;
+		return PS2_IGNORE;
 
 	if (unlikely((flags & SERIO_TIMEOUT) ||
 		     ((flags & SERIO_PARITY) &&
@@ -357,27 +354,25 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
 				     "bad data from KBC -%s%s\n",
 				     flags & SERIO_TIMEOUT ? " timeout" : "",
 				     flags & SERIO_PARITY ? " bad parity" : "");
-		ps2_cmd_aborted(&psmouse->ps2dev);
-		goto out;
+		return PS2_ERROR;
 	}
 
 	if (flags & SERIO_OOB_DATA) {
 		psmouse_handle_oob_data(psmouse, data);
-		goto out;
+		return PS2_IGNORE;
 	}
 
-	if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
-		if  (ps2_handle_ack(&psmouse->ps2dev, data))
-			goto out;
+	return PS2_PROCESS;
+}
 
-	if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
-		if  (ps2_handle_response(&psmouse->ps2dev, data))
-			goto out;
+static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data)
+{
+	struct psmouse *psmouse = container_of(ps2dev, struct psmouse, ps2dev);
 
-	pm_wakeup_event(&serio->dev, 0);
+	pm_wakeup_event(&ps2dev->serio->dev, 0);
 
 	if (psmouse->state <= PSMOUSE_RESYNCING)
-		goto out;
+		return;
 
 	if (psmouse->state == PSMOUSE_ACTIVATED &&
 	    psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
@@ -386,7 +381,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
 		psmouse->badbyte = psmouse->packet[0];
 		__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
 		psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
-		goto out;
+		return;
 	}
 
 	psmouse->packet[psmouse->pktcnt++] = data;
@@ -395,21 +390,21 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
 	if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
 		if (psmouse->pktcnt == 1) {
 			psmouse->last = jiffies;
-			goto out;
+			return;
 		}
 
 		if (psmouse->packet[1] == PSMOUSE_RET_ID ||
 		    (psmouse->protocol->type == PSMOUSE_HGPK &&
 		     psmouse->packet[1] == PSMOUSE_RET_BAT)) {
 			__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
-			serio_reconnect(serio);
-			goto out;
+			serio_reconnect(ps2dev->serio);
+			return;
 		}
 
 		/* Not a new device, try processing first byte normally */
 		psmouse->pktcnt = 1;
 		if (psmouse_handle_byte(psmouse))
-			goto out;
+			return;
 
 		psmouse->packet[psmouse->pktcnt++] = data;
 	}
@@ -424,14 +419,11 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
 		psmouse->badbyte = psmouse->packet[0];
 		__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
 		psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
-		goto out;
+		return;
 	}
 
 	psmouse->last = jiffies;
 	psmouse_handle_byte(psmouse);
-
- out:
-	return IRQ_HANDLED;
 }
 
 /*
@@ -1604,7 +1596,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 	if (!psmouse || !input_dev)
 		goto err_free;
 
-	ps2_init(&psmouse->ps2dev, serio);
+	ps2_init(&psmouse->ps2dev, serio,
+		 psmouse_pre_receive_byte, psmouse_receive_byte);
 	INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
 	psmouse->dev = input_dev;
 	snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
@@ -1786,7 +1779,7 @@ static struct serio_driver psmouse_drv = {
 	},
 	.description	= DRIVER_DESC,
 	.id_table	= psmouse_serio_ids,
-	.interrupt	= psmouse_interrupt,
+	.interrupt	= ps2_interrupt,
 	.connect	= psmouse_connect,
 	.reconnect	= psmouse_reconnect,
 	.fast_reconnect	= psmouse_fast_reconnect,
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 09eb605364bb..7c5fc853072a 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -19,9 +19,22 @@
 
 #define DRIVER_DESC	"PS/2 driver library"
 
-MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
-MODULE_DESCRIPTION("PS/2 driver library");
-MODULE_LICENSE("GPL");
+#define PS2_CMD_SETSCALE11	0x00e6
+#define PS2_CMD_SETRES		0x10e8
+#define PS2_CMD_GETID		0x02f2
+#define PS2_CMD_RESET_BAT	0x02ff
+
+#define PS2_RET_BAT		0xaa
+#define PS2_RET_ID		0x00
+#define PS2_RET_ACK		0xfa
+#define PS2_RET_NAK		0xfe
+#define PS2_RET_ERR		0xfc
+
+#define PS2_FLAG_ACK		BIT(0)	/* Waiting for ACK/NAK */
+#define PS2_FLAG_CMD		BIT(1)	/* Waiting for a command to finish */
+#define PS2_FLAG_CMD1		BIT(2)	/* Waiting for the first byte of command response */
+#define PS2_FLAG_WAITID		BIT(3)	/* Command executing is GET ID */
+#define PS2_FLAG_NAK		BIT(4)	/* Last transmission was NAKed */
 
 static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
 			   unsigned int timeout, unsigned int max_attempts)
@@ -76,14 +89,17 @@ static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
 	return error;
 }
 
-/*
- * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
- * It doesn't handle retransmission, the caller is expected to handle
+/**
+ * ps2_sendbyte - sends a byte to the device and wait for acknowledgement
+ * @ps2dev: a PS/2 device to send the data to
+ * @byte: data to be sent to the device
+ * @timeout: timeout for sending the data and receiving an acknowledge
+ *
+ * The function doesn't handle retransmission, the caller is expected to handle
  * it when needed.
  *
  * ps2_sendbyte() can only be called from a process context.
  */
-
 int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
 {
 	int retval;
@@ -99,6 +115,13 @@ int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
 }
 EXPORT_SYMBOL(ps2_sendbyte);
 
+/**
+ * ps2_begin_command - mark beginning of execution of a complex command
+ * @ps2dev: a PS/2 device executing the command
+ *
+ * Serializes a complex/compound command. Once command is finished
+ * ps2_end_command() should be called.
+ */
 void ps2_begin_command(struct ps2dev *ps2dev)
 {
 	struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
@@ -107,6 +130,10 @@ void ps2_begin_command(struct ps2dev *ps2dev)
 }
 EXPORT_SYMBOL(ps2_begin_command);
 
+/**
+ * ps2_end_command - mark end of execution of a complex command
+ * @ps2dev: a PS/2 device executing the command
+ */
 void ps2_end_command(struct ps2dev *ps2dev)
 {
 	struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex;
@@ -115,11 +142,13 @@ void ps2_end_command(struct ps2dev *ps2dev)
 }
 EXPORT_SYMBOL(ps2_end_command);
 
-/*
- * ps2_drain() waits for device to transmit requested number of bytes
- * and discards them.
+/**
+ * ps2_drain - waits for device to transmit requested number of bytes
+ * and discards them
+ * @ps2dev: the PS/2 device that should be drained
+ * @maxbytes: maximum number of bytes to be drained
+ * @timeout: time to drain the device
  */
-
 void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
 {
 	if (maxbytes > sizeof(ps2dev->cmdbuf)) {
@@ -142,11 +171,11 @@ void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
 }
 EXPORT_SYMBOL(ps2_drain);
 
-/*
- * ps2_is_keyboard_id() checks received ID byte against the list of
- * known keyboard IDs.
+/**
+ * ps2_is_keyboard_id - checks received ID byte against the list of
+ *   known keyboard IDs
+ * @id_byte: data byte that should be checked
  */
-
 bool ps2_is_keyboard_id(u8 id_byte)
 {
 	static const u8 keyboard_ids[] = {
@@ -167,7 +196,6 @@ EXPORT_SYMBOL(ps2_is_keyboard_id);
  * response and tries to reduce remaining timeout to speed up command
  * completion.
  */
-
 static int ps2_adjust_timeout(struct ps2dev *ps2dev,
 			      unsigned int command, unsigned int timeout)
 {
@@ -217,13 +245,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev,
 	return timeout;
 }
 
-/*
- * ps2_command() sends a command and its parameters to the mouse,
- * then waits for the response and puts it in the param array.
+/**
+ * __ps2_command - send a command to PS/2 device
+ * @ps2dev: the PS/2 device that should execute the command
+ * @param: a buffer containing parameters to be sent along with the command,
+ *   or place where the results of the command execution will be deposited,
+ *   or both
+ * @command: command word that encodes the command itself, as well as number of
+ *   additional parameter bytes that should be sent to the device and expected
+ *   length of the command response
  *
- * ps2_command() can only be called from a process context
+ * Not serialized. Callers should use ps2_begin_command() and ps2_end_command()
+ * to ensure proper serialization for complex commands.
  */
-
 int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 {
 	unsigned int timeout;
@@ -327,6 +361,20 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 }
 EXPORT_SYMBOL(__ps2_command);
 
+/**
+ * ps2_command - send a command to PS/2 device
+ * @ps2dev: the PS/2 device that should execute the command
+ * @param: a buffer containing parameters to be sent along with the command,
+ *   or place where the results of the command execution will be deposited,
+ *   or both
+ * @command: command word that encodes the command itself, as well as number of
+ *   additional parameter bytes that should be sent to the device and expected
+ *   length of the command response
+ *
+ * Note: ps2_command() serializes the command execution so that only one
+ * command can be executed at a time for either individual port or the entire
+ * 8042 controller.
+ */
 int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 {
 	int rc;
@@ -339,14 +387,16 @@ int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 }
 EXPORT_SYMBOL(ps2_command);
 
-/*
- * ps2_sliced_command() sends an extended PS/2 command to the mouse
- * using sliced syntax, understood by advanced devices, such as Logitech
- * or Synaptics touchpads. The command is encoded as:
+/**
+ * ps2_sliced_command - sends an extended PS/2 command to a mouse
+ * @ps2dev: the PS/2 device that should execute the command
+ * @command: command byte
+ *
+ * The command is sent using "sliced" syntax understood by advanced devices,
+ * such as Logitech or Synaptics touchpads. The command is encoded as:
  * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
  * is the command.
  */
-
 int ps2_sliced_command(struct ps2dev *ps2dev, u8 command)
 {
 	int i;
@@ -372,12 +422,22 @@ int ps2_sliced_command(struct ps2dev *ps2dev, u8 command)
 }
 EXPORT_SYMBOL(ps2_sliced_command);
 
-/*
- * ps2_init() initializes ps2dev structure
+/**
+ * ps2_init - initializes ps2dev structure
+ * @ps2dev: structure to be initialized
+ * @serio: serio port associated with the PS/2 device
+ * @pre_receive_handler: validation handler to check basic communication state
+ * @receive_handler: main protocol handler
+ *
+ * Prepares ps2dev structure for use in drivers for PS/2 devices.
  */
-
-void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio,
+	      ps2_pre_receive_handler_t pre_receive_handler,
+	      ps2_receive_handler_t receive_handler)
 {
+	ps2dev->pre_receive_handler = pre_receive_handler;
+	ps2dev->receive_handler = receive_handler;
+
 	mutex_init(&ps2dev->cmd_mutex);
 	lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth);
 	init_waitqueue_head(&ps2dev->wait);
@@ -387,11 +447,35 @@ void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
 EXPORT_SYMBOL(ps2_init);
 
 /*
- * ps2_handle_ack() is supposed to be used in interrupt handler
- * to properly process ACK/NAK of a command from a PS/2 device.
+ * ps2_handle_response() stores device's response to a command and notifies
+ * the process waiting for completion of the command. Note that there is a
+ * distinction between waiting for the first byte of the response, and
+ * waiting for subsequent bytes. It is done so that callers could shorten
+ * timeouts once first byte of response is received.
  */
+static void ps2_handle_response(struct ps2dev *ps2dev, u8 data)
+{
+	if (ps2dev->cmdcnt)
+		ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
 
-bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
+	if (ps2dev->flags & PS2_FLAG_CMD1) {
+		ps2dev->flags &= ~PS2_FLAG_CMD1;
+		if (ps2dev->cmdcnt)
+			wake_up(&ps2dev->wait);
+	}
+
+	if (!ps2dev->cmdcnt) {
+		ps2dev->flags &= ~PS2_FLAG_CMD;
+		wake_up(&ps2dev->wait);
+	}
+}
+
+/*
+ * ps2_handle_ack() processes ACK/NAK of a command from a PS/2 device,
+ * possibly applying workarounds for mice not acknowledging the "get ID"
+ * command.
+ */
+static void ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 {
 	switch (data) {
 	case PS2_RET_ACK:
@@ -436,53 +520,25 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 		 */
 		dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data);
 		ps2dev->flags &= ~PS2_FLAG_WAITID;
-		return true;
+		return;
 	}
 
 	if (!ps2dev->nak)
 		ps2dev->flags &= ~PS2_FLAG_NAK;
 
 	ps2dev->flags &= ~PS2_FLAG_ACK;
-	wake_up(&ps2dev->wait);
 
 	if (!ps2dev->nak && data != PS2_RET_ACK)
 		ps2_handle_response(ps2dev, data);
-
-	return true;
-}
-EXPORT_SYMBOL(ps2_handle_ack);
-
-/*
- * ps2_handle_response() is supposed to be used in interrupt handler
- * to properly store device's response to a command and notify process
- * waiting for completion of the command.
- */
-
-bool ps2_handle_response(struct ps2dev *ps2dev, u8 data)
-{
-	if (ps2dev->cmdcnt)
-		ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
-
-	if (ps2dev->flags & PS2_FLAG_CMD1) {
-		ps2dev->flags &= ~PS2_FLAG_CMD1;
-		if (ps2dev->cmdcnt)
-			wake_up(&ps2dev->wait);
-	}
-
-	if (!ps2dev->cmdcnt) {
-		ps2dev->flags &= ~PS2_FLAG_CMD;
+	else
 		wake_up(&ps2dev->wait);
-	}
-
-	return true;
 }
-EXPORT_SYMBOL(ps2_handle_response);
 
 /*
  * Clears state of PS/2 device after communication error by resetting majority
  * of flags and waking up waiters, if any.
  */
-void ps2_cmd_aborted(struct ps2dev *ps2dev)
+static void ps2_cleanup(struct ps2dev *ps2dev)
 {
 	unsigned long old_flags = ps2dev->flags;
 
@@ -494,6 +550,46 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev)
 
 	if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
 		wake_up(&ps2dev->wait);
+}
 
+/**
+ * ps2_interrupt - common interrupt handler for PS/2 devices
+ * @serio: serio port for the device
+ * @data: a data byte received from the device
+ * @flags: flags such as %SERIO_PARITY or %SERIO_TIMEOUT indicating state of
+ *   the data transfer
+ *
+ * ps2_interrupt() invokes pre-receive handler, optionally handles command
+ * acknowledgement and response from the device, and finally passes the data
+ * to the main protocol handler for future processing.
+ */
+irqreturn_t ps2_interrupt(struct serio *serio, u8 data, unsigned int flags) {
+	struct ps2dev *ps2dev = serio_get_drvdata(serio);
+	enum ps2_disposition rc;
+
+	rc = ps2dev->pre_receive_handler(ps2dev, data, flags);
+	switch (rc) {
+	case PS2_ERROR:
+		ps2_cleanup(ps2dev);
+		break;
+
+	case PS2_IGNORE:
+		break;
+
+	case PS2_PROCESS:
+		if (ps2dev->flags & PS2_FLAG_ACK)
+			ps2_handle_ack(ps2dev, data);
+		else if (ps2dev->flags & PS2_FLAG_CMD)
+			ps2_handle_response(ps2dev, data);
+		else
+			ps2dev->receive_handler(ps2dev, data);
+		break;
+	}
+
+	return IRQ_HANDLED;
 }
-EXPORT_SYMBOL(ps2_cmd_aborted);
+EXPORT_SYMBOL(ps2_interrupt);
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("PS/2 driver library");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/libps2.h b/include/linux/libps2.h
index 193dd53ad18b..9ca9ce4e6e64 100644
--- a/include/linux/libps2.h
+++ b/include/linux/libps2.h
@@ -8,43 +8,59 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/types.h>
 #include <linux/wait.h>
 
-#define PS2_CMD_SETSCALE11	0x00e6
-#define PS2_CMD_SETRES		0x10e8
-#define PS2_CMD_GETID		0x02f2
-#define PS2_CMD_RESET_BAT	0x02ff
+struct ps2dev;
 
-#define PS2_RET_BAT		0xaa
-#define PS2_RET_ID		0x00
-#define PS2_RET_ACK		0xfa
-#define PS2_RET_NAK		0xfe
-#define PS2_RET_ERR		0xfc
+/**
+ * enum ps2_disposition - indicates how received byte should be handled
+ * @PS2_PROCESS: pass to the main protocol handler, process normally
+ * @PS2_IGNORE: skip the byte
+ * @PS2_ERROR: do not process the byte, abort command in progress
+ */
+enum ps2_disposition {
+	PS2_PROCESS,
+	PS2_IGNORE,
+	PS2_ERROR,
+};
 
-#define PS2_FLAG_ACK		BIT(0)	/* Waiting for ACK/NAK */
-#define PS2_FLAG_CMD		BIT(1)	/* Waiting for a command to finish */
-#define PS2_FLAG_CMD1		BIT(2)	/* Waiting for the first byte of command response */
-#define PS2_FLAG_WAITID		BIT(3)	/* Command executing is GET ID */
-#define PS2_FLAG_NAK		BIT(4)	/* Last transmission was NAKed */
+typedef enum ps2_disposition (*ps2_pre_receive_handler_t)(struct ps2dev *, u8,
+							  unsigned int);
+typedef void (*ps2_receive_handler_t)(struct ps2dev *, u8);
 
+/**
+ * struct ps2dev - represents a device using PS/2 protocol
+ * @serio: a serio port used by the PS/2 device
+ * @cmd_mutex: a mutex ensuring that only one command is executing at a time
+ * @wait: a waitqueue used to signal completion from the serio interrupt handler
+ * @flags: various internal flags indicating stages of PS/2 command execution
+ * @cmdbuf: buffer holding command response
+ * @cmdcnt: outstanding number of bytes of the command response
+ * @nak: a byte transmitted by the device when it refuses command
+ * @pre_receive_handler: checks communication errors and returns disposition
+ * (&enum ps2_disposition) of the received data byte
+ * @receive_handler: main handler of particular PS/2 protocol, such as keyboard
+ *   or mouse protocol
+ */
 struct ps2dev {
 	struct serio *serio;
-
-	/* Ensures that only one command is executing at a time */
 	struct mutex cmd_mutex;
-
-	/* Used to signal completion from interrupt handler */
 	wait_queue_head_t wait;
-
 	unsigned long flags;
 	u8 cmdbuf[8];
 	u8 cmdcnt;
 	u8 nak;
+
+	ps2_pre_receive_handler_t pre_receive_handler;
+	ps2_receive_handler_t receive_handler;
 };
 
-void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio,
+	      ps2_pre_receive_handler_t pre_receive_handler,
+	      ps2_receive_handler_t receive_handler);
 int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout);
 void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout);
 void ps2_begin_command(struct ps2dev *ps2dev);
@@ -52,9 +68,8 @@ void ps2_end_command(struct ps2dev *ps2dev);
 int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
 int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command);
 int ps2_sliced_command(struct ps2dev *ps2dev, u8 command);
-bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data);
-bool ps2_handle_response(struct ps2dev *ps2dev, u8 data);
-void ps2_cmd_aborted(struct ps2dev *ps2dev);
 bool ps2_is_keyboard_id(u8 id);
 
+irqreturn_t ps2_interrupt(struct serio *serio, u8 data, unsigned int flags);
+
 #endif /* _LIBPS2_H */
-- 
2.40.1.606.ga4b1b128d6-goog


^ permalink raw reply related

* [PATCH 7/7] Input: libps2 - do not discard non-ack bytes when controlling LEDs
From: Dmitry Torokhov @ 2023-05-11 18:52 UTC (permalink / raw)
  To: linux-input; +Cc: Raul E Rangel, linux-kernel
In-Reply-To: <20230511185252.386941-1-dmitry.torokhov@gmail.com>

Upon receiving a PS/2 command the device and controller are supposed to
stop sending normal data (scancodes or movement packets) and instead
immediately start delivering ACK/NAK and command response. Unfortunately
often EC has an output buffer which may contain latched data by the time
the EC receives a command from the host. The kernel used to ignore such
data, but that may cause "stuck" keys if the data dropped happens to be a
break code or a part of a break code. This occasionally happens, for
example, on Chromebooks when the kernel tries to toggle CapsLock LED on
a keyboard while user releases Alt+Search keyboard shortcut.

Fix this by passing the first non-ACK byte to the normal handler for a
handful of PS/2 commands that are expected to be used during normal device
operation (as opposed to probe/configuration time).

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/serio/libps2.c | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 7c5fc853072a..6d78a1fe00c1 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -21,7 +21,10 @@
 
 #define PS2_CMD_SETSCALE11	0x00e6
 #define PS2_CMD_SETRES		0x10e8
+#define PS2_CMD_EX_SETLEDS	0x20eb
+#define PS2_CMD_SETLEDS		0x10ed
 #define PS2_CMD_GETID		0x02f2
+#define PS2_CMD_SETREP		0x10f3 /* Set repeat rate/set report rate */
 #define PS2_CMD_RESET_BAT	0x02ff
 
 #define PS2_RET_BAT		0xaa
@@ -35,6 +38,7 @@
 #define PS2_FLAG_CMD1		BIT(2)	/* Waiting for the first byte of command response */
 #define PS2_FLAG_WAITID		BIT(3)	/* Command executing is GET ID */
 #define PS2_FLAG_NAK		BIT(4)	/* Last transmission was NAKed */
+#define PS2_FLAG_PASS_NOACK	BIT(5)	/* Pass non-ACK byte to receive handler */
 
 static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte,
 			   unsigned int timeout, unsigned int max_attempts)
@@ -281,9 +285,28 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 
 	serio_pause_rx(ps2dev->serio);
 
-	/* Some mice do not ACK the "get ID" command, prepare to handle this. */
-	ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
 	ps2dev->cmdcnt = receive;
+
+	switch (command) {
+	case PS2_CMD_GETID:
+		/*
+		 * Some mice do not ACK the "get ID" command, prepare to
+		 * handle this.
+		 */
+		ps2dev->flags = PS2_FLAG_WAITID;
+		break;
+
+	case PS2_CMD_SETLEDS:
+	case PS2_CMD_EX_SETLEDS:
+	case PS2_CMD_SETREP:
+		ps2dev->flags = PS2_FLAG_PASS_NOACK;
+		break;
+
+	default:
+		ps2dev->flags = 0;
+		break;
+	}
+
 	if (receive) {
 		/* Indicate that we expect response to the command. */
 		ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
@@ -512,14 +535,19 @@ static void ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 		 * Do not signal errors if we get unexpected reply while
 		 * waiting for an ACK to the initial (first) command byte:
 		 * the device might not be quiesced yet and continue
-		 * delivering data.
+		 * delivering data. For certain commands (such as set leds and
+		 * set repeat rate) that can be used during normal device
+		 * operation, we even pass this data byte to the normal receive
+		 * handler.
 		 * Note that we reset PS2_FLAG_WAITID flag, so the workaround
 		 * for mice not acknowledging the Get ID command only triggers
 		 * on the 1st byte; if device spews data we really want to see
 		 * a real ACK from it.
 		 */
 		dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data);
-		ps2dev->flags &= ~PS2_FLAG_WAITID;
+		if (ps2dev->flags & PS2_FLAG_PASS_NOACK)
+			ps2dev->receive_handler(ps2dev, data);
+		ps2dev->flags &= ~(PS2_FLAG_WAITID | PS2_FLAG_PASS_NOACK);
 		return;
 	}
 
-- 
2.40.1.606.ga4b1b128d6-goog


^ permalink raw reply related

* [PATCH 4/7] Input: libps2 - fix NAK handling
From: Dmitry Torokhov @ 2023-05-11 18:52 UTC (permalink / raw)
  To: linux-input; +Cc: Raul E Rangel, linux-kernel
In-Reply-To: <20230511185252.386941-1-dmitry.torokhov@gmail.com>

Do not try to process "resend" or "reject" responses from the device
as normal response data for a command.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/serio/libps2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index d09450eca9a7..14b70a78875d 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -445,7 +445,7 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 	ps2dev->flags &= ~PS2_FLAG_ACK;
 	wake_up(&ps2dev->wait);
 
-	if (data != PS2_RET_ACK)
+	if (!ps2dev->nak && data != PS2_RET_ACK)
 		ps2_handle_response(ps2dev, data);
 
 	return true;
-- 
2.40.1.606.ga4b1b128d6-goog


^ permalink raw reply related

* [PATCH 5/7] Input: libps2 - fix aborting PS/2 commands
From: Dmitry Torokhov @ 2023-05-11 18:52 UTC (permalink / raw)
  To: linux-input; +Cc: Raul E Rangel, linux-kernel
In-Reply-To: <20230511185252.386941-1-dmitry.torokhov@gmail.com>

When aborting PS/2 command the kernel should [re]set all flags before
waking up waiters, otherwise waiting thread may read obsolete values
of flags.

Reported-by: Raul Rangel <rrangel@chromium.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/serio/libps2.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 14b70a78875d..09eb605364bb 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -478,15 +478,22 @@ bool ps2_handle_response(struct ps2dev *ps2dev, u8 data)
 }
 EXPORT_SYMBOL(ps2_handle_response);
 
+/*
+ * Clears state of PS/2 device after communication error by resetting majority
+ * of flags and waking up waiters, if any.
+ */
 void ps2_cmd_aborted(struct ps2dev *ps2dev)
 {
-	if (ps2dev->flags & PS2_FLAG_ACK)
+	unsigned long old_flags = ps2dev->flags;
+
+	/* reset all flags except last nak */
+	ps2dev->flags &= PS2_FLAG_NAK;
+
+	if (old_flags & PS2_FLAG_ACK)
 		ps2dev->nak = 1;
 
-	if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
+	if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
 		wake_up(&ps2dev->wait);
 
-	/* reset all flags except last nack */
-	ps2dev->flags &= PS2_FLAG_NAK;
 }
 EXPORT_SYMBOL(ps2_cmd_aborted);
-- 
2.40.1.606.ga4b1b128d6-goog


^ permalink raw reply related

* [PATCH 3/7] Input: libps2 - rework handling of command response
From: Dmitry Torokhov @ 2023-05-11 18:52 UTC (permalink / raw)
  To: linux-input; +Cc: Raul E Rangel, linux-kernel
In-Reply-To: <20230511185252.386941-1-dmitry.torokhov@gmail.com>

It is not entirely correct that libps2 sets PS2_FLAG_CMD1 after
the device acknowledges each byte sent to the device by the host.
Rework the code so that PS2_FLAG_CMD1 and PS2_FLAG_CMD are set only once,
at the beginning of PS/2 command execution.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/serio/libps2.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 399cda0d34f5..d09450eca9a7 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -247,14 +247,19 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
 
 	serio_pause_rx(ps2dev->serio);
 
+	/* Some mice do not ACK the "get ID" command, prepare to handle this. */
 	ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
 	ps2dev->cmdcnt = receive;
-	if (receive && param)
-		for (i = 0; i < receive; i++)
-			ps2dev->cmdbuf[(receive - 1) - i] = param[i];
+	if (receive) {
+		/* Indicate that we expect response to the command. */
+		ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
+		if (param)
+			for (i = 0; i < receive; i++)
+				ps2dev->cmdbuf[(receive - 1) - i] = param[i];
+	}
 
 	/*
-	 * Some devices (Synaptics) peform the reset before
+	 * Some devices (Synaptics) perform the reset before
 	 * ACKing the reset command, and so it can take a long
 	 * time before the ACK arrives.
 	 */
@@ -434,11 +439,8 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
 		return true;
 	}
 
-	if (!ps2dev->nak) {
+	if (!ps2dev->nak)
 		ps2dev->flags &= ~PS2_FLAG_NAK;
-		if (ps2dev->cmdcnt)
-			ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
-	}
 
 	ps2dev->flags &= ~PS2_FLAG_ACK;
 	wake_up(&ps2dev->wait);
-- 
2.40.1.606.ga4b1b128d6-goog


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox