* Re: [PATCH v3 2/2] Input: soc_button_array - Add support for newer surface devices
From: Maximilian Luz @ 2019-07-23 11:29 UTC (permalink / raw)
To: Enrico Weigelt, metux IT consult
Cc: linux-kernel, linux-input, platform-driver-x86, Dmitry Torokhov,
Hans de Goede, Chen Yu, Darren Hart, Andy Shevchenko,
Benjamin Tissoires
In-Reply-To: <a2f75544-54ce-abce-56a4-ca226dbed51f@metux.net>
On 7/22/19 10:00 AM, Enrico Weigelt, metux IT consult wrote:
> On 20.07.19 17:05, Maximilian Luz wrote:
>> Power and volume button support for 5th and 6th generation Microsoft
>> Surface devices via soc_button_array.
>>
>> Note that these devices use the same MSHW0040 device as on the Surface
>> Pro 4, however the implementation is different (GPIOs vs. ACPI
>> notifications). Thus some checking is required to ensure we only load
>> this driver on the correct devices.
>
> Could this also used on the older (pre pro4) devices (also using the
> gpios directly, and leave off acpi notifications) ?
As far as I can tell, no. The Pro 4 and Pro 3 don't have any GPIOs on
MSHW0028/MSHW0040. Book 1 has GPIOs but for a different purpose. The Pro
2 has a standard PNP0C0C power button (no idea how the volume buttons
are handled there, but also seems to be different from what I can gather
from DSDT). I can't say anything for the Pro 1 and non-Pro devices.
Maximilian
^ permalink raw reply
* [PATCH] Input: Apple SPI keyboard needs CRC16
From: Arnd Bergmann @ 2019-07-23 11:58 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Arnd Bergmann, Ronald Tschalär, Andy Shevchenko, linux-input,
linux-kernel
In some rare randconfig builds, CRC16 is disabled, which leads
to a link error:
drivers/input/keyboard/applespi.o: In function `applespi_send_cmd_msg':
applespi.c:(.text+0x449f): undefined reference to `crc16'
drivers/input/keyboard/applespi.o: In function `applespi_verify_crc':
applespi.c:(.text+0x7538): undefined reference to `crc16'
This symbol is meant to be selected for each user in Kconfig,
so do that here as well.
Fixes: 038b1a05eae6 ("Input: add Apple SPI keyboard and trackpad driver")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/input/keyboard/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 8e9c3ea9d5e7..ebb19e21473e 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -76,6 +76,7 @@ config KEYBOARD_APPLESPI
depends on ACPI && EFI
depends on SPI
depends on X86 || COMPILE_TEST
+ select CRC16
help
Say Y here if you are running Linux on any Apple MacBook8,1 or later,
or any MacBookPro13,* or MacBookPro14,*.
--
2.20.0
^ permalink raw reply related
* Re: [PATCH] Input: Apple SPI keyboard needs CRC16
From: Dmitry Torokhov @ 2019-07-23 13:42 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Ronald Tschalär, Andy Shevchenko, linux-input, linux-kernel
In-Reply-To: <20190723115905.2092687-1-arnd@arndb.de>
On Tue, Jul 23, 2019 at 01:58:45PM +0200, Arnd Bergmann wrote:
> In some rare randconfig builds, CRC16 is disabled, which leads
> to a link error:
>
> drivers/input/keyboard/applespi.o: In function `applespi_send_cmd_msg':
> applespi.c:(.text+0x449f): undefined reference to `crc16'
> drivers/input/keyboard/applespi.o: In function `applespi_verify_crc':
> applespi.c:(.text+0x7538): undefined reference to `crc16'
>
> This symbol is meant to be selected for each user in Kconfig,
> so do that here as well.
>
> Fixes: 038b1a05eae6 ("Input: add Apple SPI keyboard and trackpad driver")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Applied, thank you.
> ---
> drivers/input/keyboard/Kconfig | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index 8e9c3ea9d5e7..ebb19e21473e 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -76,6 +76,7 @@ config KEYBOARD_APPLESPI
> depends on ACPI && EFI
> depends on SPI
> depends on X86 || COMPILE_TEST
> + select CRC16
> help
> Say Y here if you are running Linux on any Apple MacBook8,1 or later,
> or any MacBookPro13,* or MacBookPro14,*.
> --
> 2.20.0
>
--
Dmitry
^ permalink raw reply
* [PATCH] HID: wacom: fix bit shift for Cintiq Companion 2
From: Aaron Armstrong Skomra @ 2019-07-23 18:09 UTC (permalink / raw)
To: linux-input, jikos, benjamin.tissoires, pinglinux, jason.gerecke
Cc: Aaron Armstrong Skomra, # v4 . 5+
The bit indicating BTN_6 on this device is overshifted
by 2 bits, resulting in the incorrect button being
reported.
Also fix copy-paste mistake in comments.
Signed-off-by: Aaron Armstrong Skomra <aaron.skomra@wacom.com>
Reviewed-by: Ping Cheng <ping.cheng@wacom.com>
Link: https://github.com/linuxwacom/xf86-input-wacom/issues/71
Fixes: c7f0522a1ad1 ("HID: wacom: Slim down wacom_intuos_pad processing")
Cc: <stable@vger.kernel.org> # v4.5+
---
drivers/hid/wacom_wac.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 8fc36a28081b..7a8ddc999a8e 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -533,14 +533,14 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
*/
buttons = (data[4] << 1) | (data[3] & 0x01);
} else if (features->type == CINTIQ_COMPANION_2) {
- /* d-pad right -> data[4] & 0x10
- * d-pad up -> data[4] & 0x20
- * d-pad left -> data[4] & 0x40
- * d-pad down -> data[4] & 0x80
- * d-pad center -> data[3] & 0x01
+ /* d-pad right -> data[2] & 0x10
+ * d-pad up -> data[2] & 0x20
+ * d-pad left -> data[2] & 0x40
+ * d-pad down -> data[2] & 0x80
+ * d-pad center -> data[1] & 0x01
*/
buttons = ((data[2] >> 4) << 7) |
- ((data[1] & 0x04) << 6) |
+ ((data[1] & 0x04) << 4) |
((data[2] & 0x0F) << 2) |
(data[1] & 0x03);
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
--
2.17.1
^ permalink raw reply related
* Reminder: 8 open syzbot bugs in input subsystem
From: Eric Biggers @ 2019-07-24 2:27 UTC (permalink / raw)
To: linux-input, Dmitry Torokhov; +Cc: linux-kernel, syzkaller-bugs
[This email was generated by a script. Let me know if you have any suggestions
to make it better, or if you want it re-generated with the latest status.]
Of the currently open syzbot reports against the upstream kernel, I've manually
marked 8 of them as possibly being bugs in the input subsystem. I've listed
these reports below, sorted by an algorithm that tries to list first the reports
most likely to be still valid, important, and actionable.
Of these 8 bugs, 6 were seen in mainline in the last week.
If you believe a bug is no longer valid, please close the syzbot report by
sending a '#syz fix', '#syz dup', or '#syz invalid' command in reply to the
original thread, as explained at https://goo.gl/tpsmEJ#status
If you believe I misattributed a bug to the input subsystem, please let me know,
and if possible forward the report to the correct people or mailing list.
Here are the bugs:
--------------------------------------------------------------------------------
Title: WARNING in aiptek_open/usb_submit_urb
Last occurred: 0 days ago
Reported: 46 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=0e35393fd821f0570b2a1663a01ac7bdcd15046a
Original thread: https://lkml.kernel.org/lkml/0000000000001abc1c058ab95b3e@google.com/T/#u
This bug has a C reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in an input USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+75cccf2b7da87fb6f84b@syzkaller.appspotmail.com
If you send any email or patch for this bug, please consider replying to the
original thread. For the git send-email command to use, or tips on how to reply
if the thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/0000000000001abc1c058ab95b3e@google.com
--------------------------------------------------------------------------------
Title: INFO: trying to register non-static key in usbtouch_open
Last occurred: 0 days ago
Reported: 0 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=19bb4d1c56f91465a4a9f5396f0607d487947838
Original thread: https://lkml.kernel.org/lkml/000000000000b69261058e589a1b@google.com/T/#u
This bug has a C reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in an input USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+f9c21a30eb9d374e30c1@syzkaller.appspotmail.com
If you send any email or patch for this bug, please reply to the original
thread. For the git send-email command to use, or tips on how to reply if the
thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000b69261058e589a1b@google.com
--------------------------------------------------------------------------------
Title: WARNING in kbtab_open/usb_submit_urb
Last occurred: 0 days ago
Reported: 0 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=ad3a473cad38ce6fbd413eac666501abdc471d31
Original thread: https://lkml.kernel.org/lkml/000000000000fa7ce2058e5c8318@google.com/T/#u
This bug has a C reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in an input USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+c7df50363aaff50aa363@syzkaller.appspotmail.com
If you send any email or patch for this bug, please reply to the original
thread. For the git send-email command to use, or tips on how to reply if the
thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000fa7ce2058e5c8318@google.com
--------------------------------------------------------------------------------
Title: WARNING in iforce_get_id_packet/usb_submit_urb
Last occurred: 4 days ago
Reported: 13 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=bd1dc4784ff2c89f9d35cd17b02a4a0e1baa1df4
Original thread: https://lkml.kernel.org/lkml/000000000000a901ed058d51adc3@google.com/T/#u
This bug has a C reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in an input USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+9584b712baf1965b590c@syzkaller.appspotmail.com
If you send any email or patch for this bug, please reply to the original
thread. For the git send-email command to use, or tips on how to reply if the
thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000a901ed058d51adc3@google.com
--------------------------------------------------------------------------------
Title: KASAN: use-after-free Read in usb_anchor_resume_wakeups
Last occurred: 0 days ago
Reported: 14 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=21616f648e5fb8ca17de9b869fec3b27270b9edb
Original thread: https://lkml.kernel.org/lkml/000000000000e9312b058d3eadb8@google.com/T/#u
Unfortunately, this bug does not have a reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in an input USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+58e201002fe1e775e1ae@syzkaller.appspotmail.com
If you send any email or patch for this bug, please reply to the original
thread. For the git send-email command to use, or tips on how to reply if the
thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000e9312b058d3eadb8@google.com
--------------------------------------------------------------------------------
Title: KASAN: use-after-free Write in usb_anchor_resume_wakeups
Last occurred: 2 days ago
Reported: 14 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=f51395a36f8f9cc43f9538a1c961b87ff7dff3d3
Original thread: https://lkml.kernel.org/lkml/000000000000ede4ad058d3ead9e@google.com/T/#u
Unfortunately, this bug does not have a reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in an input USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+6c355f8d5f11884fa38e@syzkaller.appspotmail.com
If you send any email or patch for this bug, please reply to the original
thread. For the git send-email command to use, or tips on how to reply if the
thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000ede4ad058d3ead9e@google.com
--------------------------------------------------------------------------------
Title: INFO: trying to register non-static key in usbtouch_reset_resume
Last occurred: 33 days ago
Reported: 57 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=64fd387d8358406dc0037511ee44db159f6f1605
Original thread: https://lkml.kernel.org/lkml/0000000000005463aa0589dcfb85@google.com/T/#u
This bug has a C reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in an input USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+933daad9be4e67ba91a9@syzkaller.appspotmail.com
If you send any email or patch for this bug, please consider replying to the
original thread. For the git send-email command to use, or tips on how to reply
if the thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/0000000000005463aa0589dcfb85@google.com
--------------------------------------------------------------------------------
Title: INFO: task hung in evdev_release
Last occurred: 273 days ago
Reported: 280 days ago
Branches: Mainline and others
Dashboard link: https://syzkaller.appspot.com/bug?id=ebbbff1dcac574b81f9fd5e07100a4879e5bf53d
Original thread: https://lkml.kernel.org/lkml/000000000000f1be430578524a20@google.com/T/#u
This bug has a syzkaller reproducer only.
syzbot has bisected this bug, but I think the bisection result is incorrect.
The original thread for this bug received 1 reply, 113 days ago.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+a979743610b4755d4d57@syzkaller.appspotmail.com
If you send any email or patch for this bug, please consider replying to the
original thread. For the git send-email command to use, or tips on how to reply
if the thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000f1be430578524a20@google.com
^ permalink raw reply
* Reminder: 3 open syzbot bugs in hid subsystem
From: Eric Biggers @ 2019-07-24 2:41 UTC (permalink / raw)
To: linux-input, Jiri Kosina, Benjamin Tissoires; +Cc: linux-kernel, syzkaller-bugs
[This email was generated by a script. Let me know if you have any suggestions
to make it better, or if you want it re-generated with the latest status.]
Of the currently open syzbot reports against the upstream kernel, I've manually
marked 3 of them as possibly being bugs in the hid subsystem. I've listed these
reports below, sorted by an algorithm that tries to list first the reports most
likely to be still valid, important, and actionable.
Of these 3 bugs, 2 were seen in mainline in the last week.
If you believe a bug is no longer valid, please close the syzbot report by
sending a '#syz fix', '#syz dup', or '#syz invalid' command in reply to the
original thread, as explained at https://goo.gl/tpsmEJ#status
If you believe I misattributed a bug to the hid subsystem, please let me know,
and if possible forward the report to the correct people or mailing list.
Here are the bugs:
--------------------------------------------------------------------------------
Title: KASAN: use-after-free Read in hidraw_ioctl
Last occurred: 0 days ago
Reported: 0 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=c7e345ba243bc4476aae52a3354ccbd2a90e344e
Original thread: https://lkml.kernel.org/lkml/000000000000c07378058e589a29@google.com/T/#u
This bug has a C reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in a hid USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+ded1794a717e3b235226@syzkaller.appspotmail.com
If you send any email or patch for this bug, please reply to the original
thread. For the git send-email command to use, or tips on how to reply if the
thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000c07378058e589a29@google.com
--------------------------------------------------------------------------------
Title: KASAN: use-after-free Read in usbhid_power
Last occurred: 0 days ago
Reported: 0 days ago
Branches: Mainline (with usb-fuzzer patches)
Dashboard link: https://syzkaller.appspot.com/bug?id=36143971c5b9b0341ad4018313375a5a40cb52c8
Original thread: https://lkml.kernel.org/lkml/000000000000bb4247058e589a20@google.com/T/#u
This bug has a C reproducer.
No one has replied to the original thread for this bug yet.
This looks like a bug in a hid USB driver.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+ef5de9c4f99c4edb4e49@syzkaller.appspotmail.com
If you send any email or patch for this bug, please reply to the original
thread. For the git send-email command to use, or tips on how to reply if the
thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/000000000000bb4247058e589a20@google.com
--------------------------------------------------------------------------------
Title: INFO: task hung in fsnotify_connector_destroy_workfn (2)
Last occurred: 32 days ago
Reported: 311 days ago
Branches: Mainline and others
Dashboard link: https://syzkaller.appspot.com/bug?id=d6011f00f49a2253c15a60ac102b2ea79e3ee8de
Original thread: https://lkml.kernel.org/lkml/0000000000006364200575dfc280@google.com/T/#u
This bug has a syzkaller reproducer only.
The original thread for this bug received 7 replies; the last was 301 days ago.
If you fix this bug, please add the following tag to the commit:
Reported-by: syzbot+6fb572170402d311dd39@syzkaller.appspotmail.com
If you send any email or patch for this bug, please consider replying to the
original thread. For the git send-email command to use, or tips on how to reply
if the thread isn't in your mailbox, see the "Reply instructions" at
https://lkml.kernel.org/r/0000000000006364200575dfc280@google.com
^ permalink raw reply
* [PATCH] Input: elantech - mark expected switch fall-through
From: Gustavo A. R. Silva @ 2019-07-24 17:52 UTC (permalink / raw)
To: Dmitry Torokhov, Kai-Heng Feng
Cc: linux-input, linux-kernel, Gustavo A. R. Silva
In preparation to enabling -Wimplicit-fallthrough, mark switch
cases where we are expecting to fall through.
This patch fixes the following warning:
drivers/input/mouse/elantech.c: In function 'elantech_use_host_notify':
drivers/input/mouse/elantech.c:1843:6: warning: this statement may fall through [-Wimplicit-fallthrough=]
if (dmi_get_bios_year() >= 2018)
^
drivers/input/mouse/elantech.c:1845:2: note: here
default:
^~~~~~~
Warning level 3 was used: -Wimplicit-fallthrough=3
This patch is part of the ongoing efforts to enable
-Wimplicit-fallthrough.
Notice that -Wimplicit-fallthrough will be globally
enabled in v5.3.
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
---
drivers/input/mouse/elantech.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 73544776a9ed..04fe43440a3c 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1842,6 +1842,7 @@ static bool elantech_use_host_notify(struct psmouse *psmouse,
/* SMbus implementation is stable since 2018 */
if (dmi_get_bios_year() >= 2018)
return true;
+ /* fall through */
default:
psmouse_dbg(psmouse,
"Ignoring SMBus bus provider %d\n", info->bus);
--
2.22.0
^ permalink raw reply related
* [PATCH 1/2] HID: Add Saitek X52 to the HID IDs
From: István Váradi @ 2019-07-24 18:08 UTC (permalink / raw)
Cc: István Váradi, Jiri Kosina, Benjamin Tissoires,
linux-input, linux-kernel
The USB device ID of the Saitek X52 joystick is added as a
define to hid-ids.h.
Signed-off-by: István Váradi <ivaradi@varadiistvan.hu>
---
drivers/hid/hid-ids.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0d695f8e1b2c..3a90962614ef 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -989,6 +989,7 @@
#define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7
#define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa
#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
+#define USB_DEVICE_ID_SAITEK_X52 0x075c
#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
--
2.20.1
^ permalink raw reply related
* [PATCH 2/2] HID: quirks: Set the INCREMENT_USAGE_ON_DUPLICATE quirk on Saitek X52
From: István Váradi @ 2019-07-24 18:09 UTC (permalink / raw)
Cc: István Váradi, Jiri Kosina, Benjamin Tissoires,
linux-input, linux-kernel
The Saitek X52 joystick has a pair of axes that are originally
(by the Windows driver) used as mouse pointer controls. The corresponding
usage->hid values are 0x50024 and 0x50026. Thus they are handled
as unknown axes and both get mapped to ABS_MISC. The quirk makes
the second axis to be mapped to ABS_MISC1 and thus made available
separately.
Signed-off-by: István Váradi <ivaradi@varadiistvan.hu>
---
drivers/hid/hid-quirks.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 185a577c46f6..7b18adb4922f 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -141,6 +141,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPAD), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
--
2.20.1
^ permalink raw reply related
* [PATCH] HID: Add quirk for HP X1200 PIXART OEM mouse
From: Sebastian Parschauer @ 2019-07-24 18:40 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires; +Cc: linux-input, Sebastian Parschauer, stable
The PixArt OEM mice are known for disconnecting every minute in
runlevel 1 or 3 if they are not always polled. So add quirk
ALWAYS_POLL for this one as well.
Jonathan Teh (@jonathan-teh) reported and tested the quirk.
Reference: https://github.com/sriemer/fix-linux-mouse/issues/15
Signed-off-by: Sebastian Parschauer <s.parschauer@gmx.de>
CC: stable@vger.kernel.org
---
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-quirks.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0d695f8e1b2c..2b5bdc654501 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -568,6 +568,7 @@
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
#define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 185a577c46f6..7239b9724b4b 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -92,6 +92,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
--
2.16.4
^ permalink raw reply related
* Re: [PATCH] Input: elantech - mark expected switch fall-through
From: Dmitry Torokhov @ 2019-07-24 19:25 UTC (permalink / raw)
To: Gustavo A. R. Silva; +Cc: Kai-Heng Feng, linux-input, linux-kernel
In-Reply-To: <20190724175202.GA9583@embeddedor>
Hi Gustavo,
On Wed, Jul 24, 2019 at 12:52:02PM -0500, Gustavo A. R. Silva wrote:
> In preparation to enabling -Wimplicit-fallthrough, mark switch
> cases where we are expecting to fall through.
>
> This patch fixes the following warning:
>
> drivers/input/mouse/elantech.c: In function 'elantech_use_host_notify':
> drivers/input/mouse/elantech.c:1843:6: warning: this statement may fall through [-Wimplicit-fallthrough=]
> if (dmi_get_bios_year() >= 2018)
> ^
> drivers/input/mouse/elantech.c:1845:2: note: here
> default:
> ^~~~~~~
Thank you for the patch but I already pushed out similar patch.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] Input: elantech - mark expected switch fall-through
From: Gustavo A. R. Silva @ 2019-07-24 19:29 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Kai-Heng Feng, linux-input, linux-kernel
In-Reply-To: <20190724192528.GA6859@penguin>
>
> Thank you for the patch but I already pushed out similar patch.
>
Great. Good to know it's already fixed. :)
Thanks
--
Gustavo
^ permalink raw reply
* Re: [RFC PATCH v2 0/4] Input: mpr121-polled: Add polled driver for MPR121
From: Dmitry Torokhov @ 2019-07-25 8:57 UTC (permalink / raw)
To: Michal Vokáč
Cc: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer, Fabio Estevam,
linux-input, devicetree, linux-kernel, Pengutronix Kernel Team
In-Reply-To: <ef172b24-cd27-5bb0-d8b1-718f835d0647@ysoft.com>
Hi Michal,
On Tue, May 21, 2019 at 08:51:17AM +0200, Michal Vokáč wrote:
> On 21. 05. 19 7:37, Dmitry Torokhov wrote:
> > Hi Michal,
> >
> > On Fri, May 17, 2019 at 03:12:49PM +0200, Michal Vokáč wrote:
> > > Hi,
> > >
> > > I have to deal with a situation where we have a custom i.MX6 based
> > > platform in production that uses the MPR121 touchkey controller.
> > > Unfortunately the chip is connected using only the I2C interface.
> > > The interrupt line is not used. Back in 2015 (Linux v3.14), my
> > > colleague modded the existing mpr121_touchkey.c driver to use polling
> > > instead of interrupt.
> > >
> > > For quite some time yet I am in a process of updating the product from
> > > the ancient Freescale v3.14 kernel to the latest mainline and pushing
> > > any needed changes upstream. The DT files for our imx6dl-yapp4 platform
> > > already made it into v5.1-rc.
> > >
> > > I rebased and updated our mpr121 patch to the latest mainline.
> > > It is created as a separate driver, similarly to gpio_keys_polled.
> > >
> > > The I2C device is quite susceptible to ESD. An ESD test quite often
> > > causes reset of the chip or some register randomly changes its value.
> > > The [PATCH 3/4] adds a write-through register cache. With the cache
> > > this state can be detected and the device can be re-initialied.
> > >
> > > The main question is: Is there any chance that such a polled driver
> > > could be accepted? Is it correct to implement it as a separate driver
> > > or should it be done as an option in the existing driver? I can not
> > > really imagine how I would do that though..
> > >
> > > There are also certain worries that the MPR121 chip may no longer be
> > > available in nonspecifically distant future. In case of EOL I will need
> > > to add a polled driver for an other touchkey chip. May it be already
> > > in mainline or a completely new one.
> >
> > I think that my addition of input_polled_dev was ultimately a wrong
> > thing to do. I am looking into enabling polling mode for regular input
> > devices as we then can enable polling mode in existing drivers.
>
> OK, that sounds good. Especially when one needs to switch from one chip
> to another that is already in tree, the need for a whole new polling
> driver is eliminated.
Could you please try the patch below and see if it works for your use
case? Note that I have not tried running it, but it compiles so it must
be good ;)
Thanks!
Input: add support for polling to input devices
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Separating "normal" and "polled" input devices was a mistake, as often we want
to allow the very same device work on both interrupt-driven and polled mode,
depending on the board on which the device is used.
This introduces new APIs:
- input_setup_polling
- input_set_poll_interval
- input_set_min_poll_interval
- input_set_max_poll_interval
These new APIs allow switching an input device into polled mode with sysfs
attributes matching drivers using input_polled_dev APIs that will be eventually
removed.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/Makefile | 2
drivers/input/input-poller.c | 207 ++++++++++++++++++++++++++++++++++++++++++
drivers/input/input.c | 36 ++++++-
include/linux/input.h | 10 ++
4 files changed, 247 insertions(+), 8 deletions(-)
create mode 100644 drivers/input/input-poller.c
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 40de6a7be641..e35650930371 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -6,7 +6,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input-core.o
-input-core-y := input.o input-compat.o input-mt.o ff-core.o
+input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c
new file mode 100644
index 000000000000..008d6f362d60
--- /dev/null
+++ b/drivers/input/input-poller.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support for polling mode for input devices.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include "input-poller.h"
+
+struct input_dev_poller {
+ void (*poll)(struct input_dev *dev);
+
+ unsigned int poll_interval; /* msec */
+ unsigned int poll_interval_max; /* msec */
+ unsigned int poll_interval_min; /* msec */
+
+ struct input_dev *input;
+ struct delayed_work work;
+};
+
+static void input_dev_poller_queue_work(struct input_dev_poller *poller)
+{
+ unsigned long delay;
+
+ delay = msecs_to_jiffies(poller->poll_interval);
+ if (delay >= HZ)
+ delay = round_jiffies_relative(delay);
+
+ queue_delayed_work(system_freezable_wq, &poller->work, delay);
+}
+
+static void input_dev_poller_work(struct work_struct *work)
+{
+ struct input_dev_poller *poller =
+ container_of(work, struct input_dev_poller, work.work);
+
+ poller->poll(poller->input);
+ input_dev_poller_queue_work(poller);
+}
+
+void input_dev_poller_finalize(struct input_dev_poller *poller)
+{
+ if (!poller->poll_interval)
+ poller->poll_interval = 500;
+ if (!poller->poll_interval_max)
+ poller->poll_interval_max = poller->poll_interval;
+}
+
+void input_dev_poller_start(struct input_dev_poller *poller)
+{
+ /* Only start polling if polling is enabled */
+ if (poller->poll_interval > 0) {
+ poller->poll(poller->input);
+ input_dev_poller_queue_work(poller);
+ }
+}
+
+void input_dev_poller_stop(struct input_dev_poller *poller)
+{
+ cancel_delayed_work_sync(&poller->work);
+}
+
+int input_setup_polling(struct input_dev *dev,
+ void (*poll_fn)(struct input_dev *dev))
+{
+ struct input_dev_poller *poller;
+
+ poller = kzalloc(sizeof(*poller), GFP_KERNEL);
+ if (!poller) {
+ dev_err(dev->dev.parent ?: &dev->dev,
+ "%s: unable to allocate poller structure\n", __func__);
+ return -ENOMEM;
+ }
+
+ INIT_DELAYED_WORK(&poller->work, input_dev_poller_work);
+ poller->poll = poll_fn;
+
+ dev->poller = poller;
+ return 0;
+}
+EXPORT_SYMBOL(input_setup_polling);
+
+static bool input_dev_ensure_poller(struct input_dev *dev)
+{
+ if (!dev->poller) {
+ dev_err(dev->dev.parent ?: &dev->dev,
+ "poller structure has not been set up\n");
+ return false;
+ }
+
+ return true;
+}
+
+void input_set_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval = interval;
+}
+EXPORT_SYMBOL(input_set_poll_interval);
+
+void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval_min = interval;
+}
+EXPORT_SYMBOL(input_set_min_poll_interval);
+
+void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval_max = interval;
+}
+EXPORT_SYMBOL(input_set_max_poll_interval);
+
+/* SYSFS interface */
+
+static ssize_t input_dev_get_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval);
+}
+
+static ssize_t input_dev_set_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_dev *input = to_input_dev(dev);
+ struct input_dev_poller *poller = input->poller;
+ unsigned int interval;
+ int err;
+
+ err = kstrtouint(buf, 0, &interval);
+ if (err)
+ return err;
+
+ if (interval < poller->poll_interval_min)
+ return -EINVAL;
+
+ if (interval > poller->poll_interval_max)
+ return -EINVAL;
+
+ mutex_lock(&input->mutex);
+
+ poller->poll_interval = interval;
+
+ if (input->users) {
+ cancel_delayed_work_sync(&poller->work);
+ if (poller->poll_interval > 0)
+ input_dev_poller_queue_work(poller);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR,
+ input_dev_get_poll_interval, input_dev_set_poll_interval);
+
+static ssize_t input_dev_get_poll_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval_max);
+}
+
+static DEVICE_ATTR(max, S_IRUGO, input_dev_get_poll_max, NULL);
+
+static ssize_t input_dev_get_poll_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval_min);
+}
+
+static DEVICE_ATTR(min, S_IRUGO, input_dev_get_poll_min, NULL);
+
+static umode_t input_poller_attrs_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct input_dev *input = to_input_dev(dev);
+
+ return input->poller ? attr->mode : 0;
+}
+
+static struct attribute *input_poller_attrs[] = {
+ &dev_attr_poll.attr,
+ &dev_attr_max.attr,
+ &dev_attr_min.attr,
+ NULL
+};
+
+struct attribute_group input_poller_attribute_group = {
+ .is_visible = input_poller_attrs_visible,
+ .attrs = input_poller_attrs,
+};
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7f3c5fcb9ed6..6b87c07d5981 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/rcupdate.h>
#include "input-compat.h"
+#include "input-poller.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
@@ -603,20 +604,31 @@ int input_open_device(struct input_handle *handle)
handle->open++;
- if (!dev->users++ && dev->open)
- retval = dev->open(dev);
+ if (dev->users++) {
+ /*
+ * Device is already opened, so we can exit immediately and
+ * report success.
+ */
+ goto out;
+ }
- if (retval) {
- dev->users--;
- if (!--handle->open) {
+ if (dev->open) {
+ retval = dev->open(dev);
+ if (retval) {
+ dev->users--;
+ handle->open--;
/*
* Make sure we are not delivering any more events
* through this handle
*/
synchronize_rcu();
+ goto out;
}
}
+ if (dev->poller)
+ input_dev_poller_start(dev->poller);
+
out:
mutex_unlock(&dev->mutex);
return retval;
@@ -655,8 +667,13 @@ void input_close_device(struct input_handle *handle)
__input_release_device(handle);
- if (!--dev->users && dev->close)
- dev->close(dev);
+ if (!--dev->users) {
+ if (dev->poller)
+ input_dev_poller_stop(dev->poller);
+
+ if (dev->close)
+ dev->close(dev);
+ }
if (!--handle->open) {
/*
@@ -1502,6 +1519,7 @@ static const struct attribute_group *input_dev_attr_groups[] = {
&input_dev_attr_group,
&input_dev_id_attr_group,
&input_dev_caps_attr_group,
+ &input_poller_attribute_group,
NULL
};
@@ -1511,6 +1529,7 @@ static void input_dev_release(struct device *device)
input_ff_destroy(dev);
input_mt_destroy_slots(dev);
+ kfree(dev->poller);
kfree(dev->absinfo);
kfree(dev->vals);
kfree(dev);
@@ -2135,6 +2154,9 @@ int input_register_device(struct input_dev *dev)
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
+ if (dev->poller)
+ input_dev_poller_finalize(dev->poller);
+
error = device_add(&dev->dev);
if (error)
goto err_free_vals;
diff --git a/include/linux/input.h b/include/linux/input.h
index 510e78558c10..956f32be87cc 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -21,6 +21,8 @@
#include <linux/timer.h>
#include <linux/mod_devicetable.h>
+struct input_dev_poller;
+
/**
* struct input_value - input value representation
* @type: type of value (EV_KEY, EV_ABS, etc)
@@ -147,6 +149,8 @@ struct input_dev {
struct ff_device *ff;
+ struct input_dev_poller *poller;
+
unsigned int repeat_key;
struct timer_list timer;
@@ -361,6 +365,12 @@ void input_unregister_device(struct input_dev *);
void input_reset_device(struct input_dev *);
+int input_setup_polling(struct input_dev *dev,
+ void (*poll_fn)(struct input_dev *dev));
+void input_set_poll_interval(struct input_dev *dev, unsigned int interval);
+void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval);
+void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval);
+
int __must_check input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
--
Dmitry
^ permalink raw reply related
* [Regression] 5.3-rc1: hid_llogitech_dj does not work
From: Rafael J. Wysocki @ 2019-07-25 10:07 UTC (permalink / raw)
To: Hans de Goede
Cc: Linux Kernel Mailing, Benjamin Tissoires, Jiri Kosina,
linux-input
In-Reply-To: <CAHk-=wjm7FQxdF=RKa8Xe23CLNNpbGDOACewgo8e-hwDJ8TyQg@mail.gmail.com>
Hi Hans,
This is similar to a problem I reported some time ago:
https://lore.kernel.org/lkml/2268131.Lc39eCoc3j@kreacher/
and the device affected by it is the same.
The symptom is simply that the mouse just doesn't work (no reaction). If I do
"rmmod hid_llogitech_dj", it says "Killed", but the module does go away and
the mouse starts to work (through the generic code I suppose), but then
the machine hangs on attempts to suspend (nasty).
Reverting all of the hid_llogitech_dj changes between 5.2 and 5.3-rc1:
dbcbabf7da92 HID: logitech-dj: fix return value of logi_dj_recv_query_hidpp_devices
39d21e7e0043 HID: logitech-dj: make const array template static
423dfbc362b7 HID: logitech-dj: Add usb-id for the 27MHz MX3000 receiver
helps here, but the first two don't really look like they can make any difference,
so I guess I'm an unlucky owner of a MX3000 that doesn't quite work as expected.
Any help will be appreciated. :-)
Cheers,
Rafael
^ permalink raw reply
* Re: [PATCH v3 5/7] mfd: ioc3: Add driver for SGI IOC3 chip
From: Lee Jones @ 2019-07-25 11:47 UTC (permalink / raw)
To: Thomas Bogendoerfer
Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
David S. Miller, Srinivas Kandagatla, Alessandro Zummo,
Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
linux-kernel, linux-input, netdev, linux-rtc, linux-serial
In-Reply-To: <20190613170636.6647-6-tbogendoerfer@suse.de>
On Thu, 13 Jun 2019, Thomas Bogendoerfer wrote:
> SGI IOC3 chip has integrated ethernet, keyboard and mouse interface.
> It also supports connecting a SuperIO chip for serial and parallel
> interfaces. IOC3 is used inside various SGI systemboards and add-on
> cards with different equipped external interfaces.
>
> Support for ethernet and serial interfaces were implemented inside
> the network driver. This patchset moves out the not network related
> parts to a new MFD driver, which takes care of card detection,
> setup of platform devices and interrupt distribution for the subdevices.
>
> Serial portion: Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>
> Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
> ---
> arch/mips/include/asm/sn/ioc3.h | 345 +++----
> arch/mips/sgi-ip27/ip27-timer.c | 20 -
> drivers/mfd/Kconfig | 13 +
> drivers/mfd/Makefile | 1 +
> drivers/mfd/ioc3.c | 683 +++++++++++++
A vast improvement, but still a little work to do.
> drivers/net/ethernet/sgi/Kconfig | 4 +-
> drivers/net/ethernet/sgi/ioc3-eth.c | 1932 ++++++++++++++---------------------
> drivers/tty/serial/8250/8250_ioc3.c | 98 ++
> drivers/tty/serial/8250/Kconfig | 11 +
> drivers/tty/serial/8250/Makefile | 1 +
> 10 files changed, 1693 insertions(+), 1415 deletions(-)
> create mode 100644 drivers/mfd/ioc3.c
> create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
[...]
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index a17d275bf1d4..5c9f1bd9bd0a 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1989,5 +1989,18 @@ config RAVE_SP_CORE
> Select this to get support for the Supervisory Processor
> device found on several devices in RAVE line of hardware.
>
> +config SGI_MFD_IOC3
> + tristate "SGI IOC3 core driver"
> + depends on PCI && MIPS
> + select MFD_CORE
> + help
> + This option enables basic support for the SGI IOC3-based
> + controller cards. This option does not enable any specific
> + functions on such a card, but provides necessary infrastructure
> + for other drivers to utilize.
> +
> + If you have an SGI Origin, Octane, or a PCI IOC3 card,
> + then say Y. Otherwise say N.
> +
> endmenu
> endif
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 52b1a90ff515..bba0d9eb0b18 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -249,3 +249,4 @@ obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
> obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
> obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
> obj-$(CONFIG_MFD_STMFX) += stmfx.o
> +obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
> diff --git a/drivers/mfd/ioc3.c b/drivers/mfd/ioc3.c
> new file mode 100644
> index 000000000000..0c0d1b3475d0
> --- /dev/null
> +++ b/drivers/mfd/ioc3.c
> @@ -0,0 +1,683 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * SGI IOC3 multifunction device driver
> + *
> + * Copyright (C) 2018, 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
> + *
> + * Based on work by:
> + * Stanislaw Skowronek <skylark@unaligned.org>
> + * Joshua Kinard <kumba@gentoo.org>
> + * Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
> + * Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/core.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/sgi-w1.h>
> +#include <linux/rtc/ds1685.h>
> +
> +#include <asm/pci/bridge.h>
> +#include <asm/sn/ioc3.h>
> +
> +#define IOC3_IRQ_SERIAL_A 6
> +#define IOC3_IRQ_SERIAL_B 15
> +#define IOC3_IRQ_KBD 22
> +#define IOC3_IRQ_ETH_DOMAIN 23
> +
> +static int ioc3_serial_id;
> +static int ioc3_eth_id;
> +static int ioc3_kbd_id;
> +
> +struct ioc3_priv_data {
> + struct irq_domain *domain;
> + struct ioc3 __iomem *regs;
> + struct pci_dev *pdev;
> + int domain_irq;
> +};
> +
> +static void ioc3_irq_ack(struct irq_data *d)
> +{
> + struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
> + unsigned int hwirq = irqd_to_hwirq(d);
> +
> + writel(BIT(hwirq), &ipd->regs->sio_ir);
> +}
> +
> +static void ioc3_irq_mask(struct irq_data *d)
> +{
> + struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
> + unsigned int hwirq = irqd_to_hwirq(d);
> +
> + writel(BIT(hwirq), &ipd->regs->sio_iec);
> +}
> +
> +static void ioc3_irq_unmask(struct irq_data *d)
> +{
> + struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
> + unsigned int hwirq = irqd_to_hwirq(d);
> +
> + writel(BIT(hwirq), &ipd->regs->sio_ies);
> +}
> +
> +static struct irq_chip ioc3_irq_chip = {
> + .name = "IOC3",
> + .irq_ack = ioc3_irq_ack,
> + .irq_mask = ioc3_irq_mask,
> + .irq_unmask = ioc3_irq_unmask,
> +};
> +
> +#define IOC3_LVL_MASK (BIT(IOC3_IRQ_SERIAL_A) | BIT(IOC3_IRQ_SERIAL_B))
> +
> +static int ioc3_irq_domain_map(struct irq_domain *d, unsigned int irq,
> + irq_hw_number_t hwirq)
> +{
> + /* use level irqs for every interrupt contained in IOC3_LVL_MASK */
Nit: Could you use proper grammar (less the full stops) in the
comments please? Start with an uppercase character and things like
"irq" should be "IRQ", etc.
> + if (BIT(hwirq) & IOC3_LVL_MASK)
> + irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_level_irq);
> + else
> + irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_edge_irq);
> +
> + irq_set_chip_data(irq, d->host_data);
> + return 0;
> +}
> +
> +static const struct irq_domain_ops ioc3_irq_domain_ops = {
> + .map = ioc3_irq_domain_map,
> +};
> +
> +static void ioc3_irq_handler(struct irq_desc *desc)
> +{
> + struct irq_domain *domain = irq_desc_get_handler_data(desc);
> + struct ioc3_priv_data *ipd = domain->host_data;
> + struct ioc3 __iomem *regs = ipd->regs;
> + u32 pending, mask;
> + unsigned int irq;
> +
> + pending = readl(®s->sio_ir);
> + mask = readl(®s->sio_ies);
> + pending &= mask; /* mask off not enabled but pending irqs */
> +
> + if (mask & BIT(IOC3_IRQ_ETH_DOMAIN))
> + /* if eth irq is enabled we need to check in eth irq regs */
> + if (readl(®s->eth.eisr) & readl(®s->eth.eier))
> + pending |= IOC3_IRQ_ETH_DOMAIN;
> +
> + if (pending) {
> + irq = irq_find_mapping(domain, __ffs(pending));
> + if (irq)
> + generic_handle_irq(irq);
> + } else {
> + spurious_interrupt();
> + }
> +}
> +
> +/*
> + * System boards/BaseIOs use more interrupt pins of the bridge asic
"ASIC"
> + * to which the IOC3 is connected. Since the IOC3 MFD driver
> + * knows wiring of these extra pins, we use the map_irq function
> + * to get interrupts activated
> + */
> +static int ioc3_map_irq(struct pci_dev *pdev, int pin)
> +{
> + struct pci_host_bridge *hbrg = pci_find_host_bridge(pdev->bus);
> +
> + return hbrg->map_irq(pdev, pin, 0);
> +}
> +
> +static int ioc3_irq_domain_setup(struct ioc3_priv_data *ipd, int irq)
> +{
> + struct irq_domain *domain;
> + struct fwnode_handle *fn;
> +
> + fn = irq_domain_alloc_named_fwnode("IOC3");
> + if (!fn)
> + goto err;
> +
> + domain = irq_domain_create_linear(fn, 24, &ioc3_irq_domain_ops, ipd);
> + if (!domain)
> + goto err;
> +
> + irq_domain_free_fwnode(fn);
> + ipd->domain = domain;
> +
> + irq_set_chained_handler_and_data(irq, ioc3_irq_handler, domain);
> + ipd->domain_irq = irq;
> + return 0;
> +err:
> + dev_err(&ipd->pdev->dev, "irq domain setup failed\n");
> + return -ENOMEM;
> +}
> +
> +static struct resource ioc3_uarta_resources[] = {
> + DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta),
> + sizeof_field(struct ioc3, sregs.uarta)),
> + DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_A)
> +};
> +
> +static struct resource ioc3_uartb_resources[] = {
> + DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uartb),
> + sizeof_field(struct ioc3, sregs.uartb)),
> + DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_B)
> +};
> +
> +static struct mfd_cell ioc3_serial_cells[] = {
> + {
> + .name = "ioc3-serial8250",
> + .resources = ioc3_uarta_resources,
> + .num_resources = ARRAY_SIZE(ioc3_uarta_resources),
> + .id = 0,
> + },
> + {
> + .name = "ioc3-serial8250",
> + .resources = ioc3_uartb_resources,
> + .num_resources = ARRAY_SIZE(ioc3_uartb_resources),
> + .id = 1,
Any reason for not using PLATFORM_DEVID_AUTO.
> + }
> +};
> +
> +static int ioc3_serial_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret;
> +
> + /* set gpio pins for RS232/RS422 mode selection */
> + writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL,
> + &ipd->regs->gpcr_s);
> + /* select RS232 mode for uart a */
> + writel(0, &ipd->regs->gppr[6]);
> + /* select RS232 mode for uart b */
> + writel(0, &ipd->regs->gppr[7]);
> +
> + /* switch both ports to 16650 mode */
> + writel(readl(&ipd->regs->port_a.sscr) & ~SSCR_DMA_EN,
> + &ipd->regs->port_a.sscr);
> + writel(readl(&ipd->regs->port_b.sscr) & ~SSCR_DMA_EN,
> + &ipd->regs->port_b.sscr);
> + udelay(1000); /* wait until mode switch is done */
> +
> + ret = mfd_add_devices(&ipd->pdev->dev, ioc3_serial_id,
Any reason for not using PLATFORM_DEVID_AUTO.
> + ioc3_serial_cells, ARRAY_SIZE(ioc3_serial_cells),
> + &ipd->pdev->resource[0], 0, ipd->domain);
> + if (ret) {
> + dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n");
> + return ret;
> + }
> + ioc3_serial_id += 2;
When is this likely to be re-read?
> + return 0;
> +}
> +
> +static struct resource ioc3_kbd_resources[] = {
> + DEFINE_RES_MEM(offsetof(struct ioc3, serio),
> + sizeof_field(struct ioc3, serio)),
> + DEFINE_RES_IRQ(IOC3_IRQ_KBD)
> +};
> +
> +static struct mfd_cell ioc3_kbd_cells[] = {
> + {
> + .name = "ioc3-kbd",
> + .resources = ioc3_kbd_resources,
> + .num_resources = ARRAY_SIZE(ioc3_kbd_resources),
> + }
> +};
> +
> +static int ioc3_kbd_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret;
> +
> + ret = mfd_add_devices(&ipd->pdev->dev, ioc3_kbd_id, ioc3_kbd_cells,
> + ARRAY_SIZE(ioc3_kbd_cells),
> + &ipd->pdev->resource[0], 0, ipd->domain);
> + if (ret) {
> + dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n");
> + return ret;
> + }
> + ioc3_kbd_id++;
Nit: '\n' here
> + return 0;
> +}
> +
> +static struct resource ioc3_eth_resources[] = {
> + DEFINE_RES_MEM(offsetof(struct ioc3, eth),
> + sizeof_field(struct ioc3, eth)),
> + DEFINE_RES_MEM(offsetof(struct ioc3, ssram),
> + sizeof_field(struct ioc3, ssram)),
> + DEFINE_RES_IRQ(0)
> +};
> +
> +static struct resource ioc3_w1_resources[] = {
> + DEFINE_RES_MEM(offsetof(struct ioc3, mcr),
> + sizeof_field(struct ioc3, mcr)),
> +};
> +static struct sgi_w1_platform_data ioc3_w1_platform_data;
> +
> +static struct mfd_cell ioc3_eth_cells[] = {
> + {
> + .name = "ioc3-eth",
> + .resources = ioc3_eth_resources,
> + .num_resources = ARRAY_SIZE(ioc3_eth_resources),
> + },
> + {
> + .name = "sgi_w1",
> + .resources = ioc3_w1_resources,
> + .num_resources = ARRAY_SIZE(ioc3_w1_resources),
> + .platform_data = &ioc3_w1_platform_data,
> + .pdata_size = sizeof(ioc3_w1_platform_data),
> + }
> +};
> +
> +static int ioc3_eth_setup(struct ioc3_priv_data *ipd, bool use_domain)
> +{
> + int irq = ipd->pdev->irq;
> + int ret;
> +
> + /* enable One-Wire bus */
> + writel(GPCR_MLAN_EN, &ipd->regs->gpcr_s);
> +
> + /* generate unique identifier */
> + snprintf(ioc3_w1_platform_data.dev_id,
> + sizeof(ioc3_w1_platform_data.dev_id), "ioc3-%012llx",
> + ipd->pdev->resource->start);
> +
> + if (use_domain)
> + irq = irq_create_mapping(ipd->domain, IOC3_IRQ_ETH_DOMAIN);
> +
> + ret = mfd_add_devices(&ipd->pdev->dev, ioc3_eth_id, ioc3_eth_cells,
> + ARRAY_SIZE(ioc3_eth_cells),
> + &ipd->pdev->resource[0], irq, NULL);
> + if (ret) {
> + dev_err(&ipd->pdev->dev, "Failed to add ETH/W1 subdev\n");
> + return ret;
> + }
> +
Nit: Remove this line and place it below:
> + ioc3_eth_id++;
Nit: '\n' here
> + return 0;
> +}
> +
> +#define M48T35_REG_SIZE 32768 /* size of m48t35 registers */
> +
> +static struct resource ioc3_m48t35_resources[] = {
> + DEFINE_RES_MEM(IOC3_BYTEBUS_DEV0, M48T35_REG_SIZE)
> +};
> +
> +static struct mfd_cell ioc3_m48t35_cells[] = {
> + {
> + .name = "rtc-m48t35",
> + .resources = ioc3_m48t35_resources,
> + .num_resources = ARRAY_SIZE(ioc3_m48t35_resources),
> + }
> +};
> +
> +static int ioc3_m48t35_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret;
> +
> + ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO,
> + ioc3_m48t35_cells, ARRAY_SIZE(ioc3_m48t35_cells),
> + &ipd->pdev->resource[0], 0, ipd->domain);
> + if (ret)
> + dev_err(&ipd->pdev->dev, "Failed to add M48T35 subdev\n");
> +
> + return ret;
> +}
> +
> +/*
> + * On IP30 the RTC (a DS1687) is behind the IOC3 on the generic
> + * ByteBus regions. We have to write the RTC address of interest to
> + * IOC3_BYTEBUS_DEV1, then read the data from IOC3_BYTEBUS_DEV2.
> + * rtc->regs already points to IOC3_BYTEBUS_DEV1.
> + */
> +#define IP30_RTC_ADDR(rtc) (rtc->regs)
> +#define IP30_RTC_DATA(rtc) ((rtc->regs) + IOC3_BYTEBUS_DEV2 - IOC3_BYTEBUS_DEV1)
> +
> +static u8 ip30_rtc_read(struct ds1685_priv *rtc, int reg)
> +{
> + writeb((reg & 0x7f), IP30_RTC_ADDR(rtc));
> + return readb(IP30_RTC_DATA(rtc));
> +}
> +
> +static void ip30_rtc_write(struct ds1685_priv *rtc, int reg, u8 value)
> +{
> + writeb((reg & 0x7f), IP30_RTC_ADDR(rtc));
> + writeb(value, IP30_RTC_DATA(rtc));
> +}
Why is this not in the RTC driver?
> +static struct ds1685_rtc_platform_data ip30_rtc_platform_data = {
> + .bcd_mode = false,
> + .no_irq = false,
> + .uie_unsupported = true,
> + .alloc_io_resources = true,
> + .plat_read = ip30_rtc_read,
> + .plat_write = ip30_rtc_write,
Call-backs in a non-subsystem API is pretty ugly IMHO.
Where are these called from?
> +};
> +
> +static struct resource ioc3_rtc_ds1685_resources[] = {
> + DEFINE_RES_MEM(IOC3_BYTEBUS_DEV1,
> + IOC3_BYTEBUS_DEV2 - IOC3_BYTEBUS_DEV1 + 1),
> + DEFINE_RES_IRQ(0)
> +};
> +
> +static struct mfd_cell ioc3_ds1685_cells[] = {
> + {
> + .name = "rtc-ds1685",
> + .resources = ioc3_rtc_ds1685_resources,
> + .num_resources = ARRAY_SIZE(ioc3_rtc_ds1685_resources),
> + .platform_data = &ip30_rtc_platform_data,
> + .pdata_size = sizeof(ip30_rtc_platform_data),
> + .id = -1,
Use the #define. Same goes for below.
> + }
> +};
> +
> +static int ioc3_ds1685_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret, irq;
> +
> + irq = ioc3_map_irq(ipd->pdev, 6);
Nit: '\n' here
> + ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_ds1685_cells,
> + ARRAY_SIZE(ioc3_ds1685_cells),
> + &ipd->pdev->resource[0], irq, NULL);
> + if (ret)
> + dev_err(&ipd->pdev->dev, "Failed to add DS1685 subdev\n");
> +
> + return ret;
> +};
> +
> +
> +static struct resource ioc3_leds_resources[] = {
> + DEFINE_RES_MEM(offsetof(struct ioc3, gppr[0]),
> + sizeof_field(struct ioc3, gppr[0])),
> + DEFINE_RES_MEM(offsetof(struct ioc3, gppr[1]),
> + sizeof_field(struct ioc3, gppr[1])),
> +};
> +
> +static struct mfd_cell ioc3_led_cells[] = {
> + {
> + .name = "ip30-leds",
> + .resources = ioc3_leds_resources,
> + .num_resources = ARRAY_SIZE(ioc3_leds_resources),
> + .id = -1,
> + }
> +};
> +
> +static int ioc3_led_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret;
> +
> + ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_led_cells,
> + ARRAY_SIZE(ioc3_led_cells),
> + &ipd->pdev->resource[0], 0, ipd->domain);
> + if (ret)
> + dev_err(&ipd->pdev->dev, "Failed to add LED subdev\n");
Nit: '\n' here
> + return ret;
> +}
> +
> +static int ip27_baseio_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret, io_irq;
> +
> + io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
> + ret = ioc3_irq_domain_setup(ipd, io_irq);
> + if (ret)
> + return ret;
Nit: '\n' here
> + ret = ioc3_eth_setup(ipd, false);
> + if (ret)
> + return ret;
Nit: '\n' here
> + ret = ioc3_serial_setup(ipd);
> + if (ret)
> + return ret;
Nit: '\n' here
Etc, etc, etc ... same for all of the instances below.
> + return ioc3_m48t35_setup(ipd);
> +}
> +
> +static int ip27_baseio6g_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret, io_irq;
> +
> + io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
> + ret = ioc3_irq_domain_setup(ipd, io_irq);
> + if (ret)
> + return ret;
> + ret = ioc3_eth_setup(ipd, false);
> + if (ret)
> + return ret;
> + ret = ioc3_serial_setup(ipd);
> + if (ret)
> + return ret;
> + ret = ioc3_m48t35_setup(ipd);
> + if (ret)
> + return ret;
> + return ioc3_kbd_setup(ipd);
> +}
> +
> +static int ip27_mio_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret;
> +
> + ret = ioc3_irq_domain_setup(ipd, ipd->pdev->irq);
> + if (ret)
> + return ret;
> + ret = ioc3_serial_setup(ipd);
> + if (ret)
> + return ret;
> + return ioc3_kbd_setup(ipd);
> +}
> +
> +static int ip29_sysboard_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret, io_irq;
> +
> + io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 1);
> + ret = ioc3_irq_domain_setup(ipd, io_irq);
> + if (ret)
> + return ret;
> + ret = ioc3_eth_setup(ipd, false);
> + if (ret)
> + return ret;
> + ret = ioc3_serial_setup(ipd);
> + if (ret)
> + return ret;
> + ret = ioc3_m48t35_setup(ipd);
> + if (ret)
> + return ret;
> + return ioc3_kbd_setup(ipd);
> +}
> +
> +static int ip30_sysboard_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret, io_irq;
> +
> + io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
> + ret = ioc3_irq_domain_setup(ipd, io_irq);
> + if (ret)
> + return ret;
> + ret = ioc3_eth_setup(ipd, false);
> + if (ret)
> + return ret;
> + ret = ioc3_serial_setup(ipd);
> + if (ret)
> + return ret;
> + ret = ioc3_kbd_setup(ipd);
> + if (ret)
> + return ret;
> + ret = ioc3_ds1685_setup(ipd);
> + if (ret)
> + return ret;
> + return ioc3_led_setup(ipd);
> +}
> +
> +static int ioc3_menet_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret, io_irq;
> +
> + io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 4);
> + ret = ioc3_irq_domain_setup(ipd, io_irq);
> + if (ret)
> + return ret;
> + ret = ioc3_eth_setup(ipd, false);
> + if (ret)
> + return ret;
> + return ioc3_serial_setup(ipd);
> +}
> +
> +static int ioc3_menet4_setup(struct ioc3_priv_data *ipd)
> +{
> + return ioc3_eth_setup(ipd, false);
> +}
> +
> +static int ioc3_cad_duo_setup(struct ioc3_priv_data *ipd)
> +{
> + int ret;
> +
> + ret = ioc3_irq_domain_setup(ipd, ipd->pdev->irq);
> + if (ret)
> + return ret;
> + ret = ioc3_eth_setup(ipd, true);
> + if (ret)
> + return ret;
> + return ioc3_kbd_setup(ipd);
> +}
> +
> +#define IOC3_SID(_name, _sid, _setup) \
> + { \
> + .name = _name, \
> + .sid = (PCI_VENDOR_ID_SGI << 16) | IOC3_SUBSYS_ ## _sid, \
> + .setup = _setup, \
> + }
> +
> +static struct {
> + const char *name;
> + u32 sid;
> + int (*setup)(struct ioc3_priv_data *ipd);
> +} ioc3_infos[] = {
IMHO it's neater if you separate the definition and static data part.
> + IOC3_SID("IP27 BaseIO6G", IP27_BASEIO6G, &ip27_baseio6g_setup),
> + IOC3_SID("IP27 MIO", IP27_MIO, &ip27_mio_setup),
> + IOC3_SID("IP27 BaseIO", IP27_BASEIO, &ip27_baseio_setup),
> + IOC3_SID("IP29 System Board", IP29_SYSBOARD, &ip29_sysboard_setup),
> + IOC3_SID("IP30 System Board", IP30_SYSBOARD, &ip30_sysboard_setup),
> + IOC3_SID("MENET", MENET, &ioc3_menet_setup),
> + IOC3_SID("MENET4", MENET4, &ioc3_menet4_setup)
> +};
> +
> +static int ioc3_setup(struct ioc3_priv_data *ipd)
> +{
> + u32 sid;
> + int i;
> +
> + /* Clear IRQs */
> + writel(~0, &ipd->regs->sio_iec);
> + writel(~0, &ipd->regs->sio_ir);
> + writel(0, &ipd->regs->eth.eier);
> + writel(~0, &ipd->regs->eth.eisr);
> +
> + /* read subsystem vendor id and subsystem id */
> + pci_read_config_dword(ipd->pdev, PCI_SUBSYSTEM_VENDOR_ID, &sid);
> +
> + for (i = 0; i < ARRAY_SIZE(ioc3_infos); i++)
> + if (sid == ioc3_infos[i].sid) {
> + pr_info("ioc3: %s\n", ioc3_infos[i].name);
> + return ioc3_infos[i].setup(ipd);
> + }
> +
> + /* treat everything not identified by PCI subid as CAD DUO */
> + pr_info("ioc3: CAD DUO\n");
> + return ioc3_cad_duo_setup(ipd);
> +}
> +
> +static int ioc3_mfd_probe(struct pci_dev *pdev,
> + const struct pci_device_id *pci_id)
> +{
> + struct ioc3_priv_data *ipd;
> + struct ioc3 __iomem *regs;
> + int ret;
> +
> + ret = pci_enable_device(pdev);
> + if (ret)
> + return ret;
> +
> + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
What does 64 mean here? Define it perhaps?
> + pci_set_master(pdev);
> +
> + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
> + if (ret) {
> + dev_warn(&pdev->dev, "Warning: couldn_t set 64-bit DMA mask\n");
Remove the "Warning:" part please.
"Failed to set 64-bit DMA mask - trying 32-bit" ?
> + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
> + if (ret) {
> + dev_err(&pdev->dev, "Can't set DMA mask, aborting\n");
> + return ret;
> + }
> + }
> +
> + /* Set up per-IOC3 data */
> + ipd = devm_kzalloc(&pdev->dev, sizeof(struct ioc3_priv_data),
> + GFP_KERNEL);
> + if (!ipd) {
> + ret = -ENOMEM;
> + goto out_disable_device;
> + }
> + ipd->pdev = pdev;
> +
> + /*
> + * Map all IOC3 registers. These are shared between subdevices
> + * so the main IOC3 module manages them.
> + */
> + regs = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0),
> + pci_resource_len(pdev, 0));
> + if (!regs) {
> + pr_warn("ioc3: Unable to remap PCI BAR for %s.\n",
> + pci_name(pdev));
Why are you using pr_warn() here?
> + ret = -ENOMEM;
> + goto out_disable_device;
> + }
> + ipd->regs = regs;
> +
> + /* Track PCI-device specific data */
> + pci_set_drvdata(pdev, ipd);
> +
> + ret = ioc3_setup(ipd);
> + if (ret)
> + goto out_disable_device;
> +
> + return 0;
> +
> +out_disable_device:
> + pci_disable_device(pdev);
> + return ret;
> +}
> +
> +static void ioc3_mfd_remove(struct pci_dev *pdev)
> +{
> + struct ioc3_priv_data *ipd;
> +
> + ipd = pci_get_drvdata(pdev);
> +
> + /* Clear and disable all IRQs */
> + writel(~0, &ipd->regs->sio_iec);
> + writel(~0, &ipd->regs->sio_ir);
> +
> + /* Release resources */
> + if (ipd->domain) {
> + irq_domain_remove(ipd->domain);
> + free_irq(ipd->domain_irq, (void *)ipd);
> + }
> + pci_disable_device(pdev);
> +}
> +
> +static struct pci_device_id ioc3_mfd_id_table[] = {
> + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
> + { 0, },
> +};
> +MODULE_DEVICE_TABLE(pci, ioc3_mfd_id_table);
> +
> +static struct pci_driver ioc3_mfd_driver = {
> + .name = "IOC3",
> + .id_table = ioc3_mfd_id_table,
> + .probe = ioc3_mfd_probe,
> + .remove = ioc3_mfd_remove,
> +};
> +
> +module_pci_driver(ioc3_mfd_driver);
> +
> +MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
> +MODULE_DESCRIPTION("SGI IOC3 MFD driver");
> +MODULE_LICENSE("GPL");
GPL v2 ?
--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* general protection fault in holtek_kbd_input_event
From: syzbot @ 2019-07-25 12:08 UTC (permalink / raw)
To: andreyknvl, benjamin.tissoires, jikos, linux-input, linux-kernel,
linux-usb, syzkaller-bugs
Hello,
syzbot found the following crash on:
HEAD commit: 6a3599ce usb-fuzzer: main usb gadget fuzzer driver
git tree: https://github.com/google/kasan.git usb-fuzzer
console output: https://syzkaller.appspot.com/x/log.txt?x=14e6d3d0600000
kernel config: https://syzkaller.appspot.com/x/.config?x=700ca426ab83faae
dashboard link: https://syzkaller.appspot.com/bug?extid=965152643a75a56737be
compiler: gcc (GCC) 9.0.0 20181231 (experimental)
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=1663f8cc600000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=145f2978600000
IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+965152643a75a56737be@syzkaller.appspotmail.com
kasan: CONFIG_KASAN_INLINE enabled
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] SMP KASAN
CPU: 0 PID: 9738 Comm: syz-executor849 Not tainted 5.2.0-rc6+ #15
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
RIP: 0010:usb_get_intfdata include/linux/usb.h:265 [inline]
RIP: 0010:holtek_kbd_input_event+0xb7/0x1a0 drivers/hid/hid-holtek-kbd.c:127
Code: 48 8b 7b 40 31 f6 48 81 ef a0 00 00 00 e8 c1 7b ee fe 48 ba 00 00 00
00 00 fc ff df 48 8d b8 a8 00 00 00 48 89 f9 48 c1 e9 03 <80> 3c 11 00 0f
85 ab 00 00 00 48 8b 98 a8 00 00 00 48 b8 00 00 00
RSP: 0018:ffff8881ce297af8 EFLAGS: 00010002
RAX: 0000000000000000 RBX: ffff8881d530bbb0 RCX: 0000000000000015
RDX: dffffc0000000000 RSI: ffffffff8345640b RDI: 00000000000000a8
RBP: 0000000000000014 R08: ffff8881d1be1800 R09: ffffed103b646748
R10: ffffed103b646747 R11: ffff8881db233a3b R12: 0000000000000000
R13: 0000000000000004 R14: ffffffff8456e680 R15: 0000000000000003
FS: 00007f9ebaadb700(0000) GS:ffff8881db200000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f646c43c000 CR3: 00000001ce2a8000 CR4: 00000000001406f0
Call Trace:
input_handle_event+0x6a9/0x11c0 drivers/input/input.c:374
input_inject_event+0x270/0x304 drivers/input/input.c:462
evdev_do_ioctl drivers/input/evdev.c:1102 [inline]
evdev_ioctl_handler+0x6c4/0x19b0 drivers/input/evdev.c:1303
vfs_ioctl fs/ioctl.c:46 [inline]
file_ioctl fs/ioctl.c:509 [inline]
do_vfs_ioctl+0xcda/0x12e0 fs/ioctl.c:696
ksys_ioctl+0x9b/0xc0 fs/ioctl.c:713
__do_sys_ioctl fs/ioctl.c:720 [inline]
__se_sys_ioctl fs/ioctl.c:718 [inline]
__x64_sys_ioctl+0x6f/0xb0 fs/ioctl.c:718
do_syscall_64+0xb7/0x560 arch/x86/entry/common.c:301
entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x44e599
Code: e8 3c e6 ff ff 48 83 c4 18 c3 0f 1f 80 00 00 00 00 48 89 f8 48 89 f7
48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff
ff 0f 83 cb ca fb ff c3 66 2e 0f 1f 84 00 00 00 00
RSP: 002b:00007f9ebaadace8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00000000006e0c28 RCX: 000000000044e599
RDX: 0000000020000040 RSI: 0000000040084503 RDI: 0000000000000004
RBP: 00000000006e0c20 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00000000006e0c2c
R13: 00007ffe21581f9f R14: 00007f9ebaadb9c0 R15: 0000000000000000
Modules linked in:
---[ end trace 48abaec9fafcd397 ]---
RIP: 0010:usb_get_intfdata include/linux/usb.h:265 [inline]
RIP: 0010:holtek_kbd_input_event+0xb7/0x1a0 drivers/hid/hid-holtek-kbd.c:127
Code: 48 8b 7b 40 31 f6 48 81 ef a0 00 00 00 e8 c1 7b ee fe 48 ba 00 00 00
00 00 fc ff df 48 8d b8 a8 00 00 00 48 89 f9 48 c1 e9 03 <80> 3c 11 00 0f
85 ab 00 00 00 48 8b 98 a8 00 00 00 48 b8 00 00 00
RSP: 0018:ffff8881ce297af8 EFLAGS: 00010002
RAX: 0000000000000000 RBX: ffff8881d530bbb0 RCX: 0000000000000015
RDX: dffffc0000000000 RSI: ffffffff8345640b RDI: 00000000000000a8
RBP: 0000000000000014 R08: ffff8881d1be1800 R09: ffffed103b646748
R10: ffffed103b646747 R11: ffff8881db233a3b R12: 0000000000000000
R13: 0000000000000004 R14: ffffffff8456e680 R15: 0000000000000003
FS: 00007f9ebaadb700(0000) GS:ffff8881db200000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f646c43c000 CR3: 00000001ce2a8000 CR4: 00000000001406f0
---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
syzbot can test patches for this bug, for details see:
https://goo.gl/tpsmEJ#testing-patches
^ permalink raw reply
* WARNING: ODEBUG bug in __free_pages_ok
From: syzbot @ 2019-07-25 12:08 UTC (permalink / raw)
To: andreyknvl, benjamin.tissoires, jikos, linux-input, linux-kernel,
linux-usb, syzkaller-bugs
Hello,
syzbot found the following crash on:
HEAD commit: 6a3599ce usb-fuzzer: main usb gadget fuzzer driver
git tree: https://github.com/google/kasan.git usb-fuzzer
console output: https://syzkaller.appspot.com/x/log.txt?x=10d72ef0600000
kernel config: https://syzkaller.appspot.com/x/.config?x=700ca426ab83faae
dashboard link: https://syzkaller.appspot.com/bug?extid=6ff9bba63b987471b8be
compiler: gcc (GCC) 9.0.0 20181231 (experimental)
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=144edb68600000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=14cd0e64600000
IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+6ff9bba63b987471b8be@syzkaller.appspotmail.com
usb 1-1: USB disconnect, device number 2
------------[ cut here ]------------
ODEBUG: free active (active state 0) object type: timer_list hint:
hid_retry_timeout+0x0/0xd0 drivers/hid/usbhid/hid-core.c:716
WARNING: CPU: 1 PID: 21 at lib/debugobjects.c:325
debug_print_object+0x160/0x250 lib/debugobjects.c:325
Kernel panic - not syncing: panic_on_warn set ...
CPU: 1 PID: 21 Comm: kworker/1:1 Not tainted 5.2.0-rc6+ #15
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
Workqueue: usb_hub_wq hub_event
Call Trace:
__dump_stack lib/dump_stack.c:77 [inline]
dump_stack+0xca/0x13e lib/dump_stack.c:113
panic+0x292/0x6c9 kernel/panic.c:219
__warn.cold+0x20/0x4b kernel/panic.c:576
report_bug+0x262/0x2a0 lib/bug.c:186
fixup_bug arch/x86/kernel/traps.c:179 [inline]
fixup_bug arch/x86/kernel/traps.c:174 [inline]
do_error_trap+0x12b/0x1e0 arch/x86/kernel/traps.c:272
do_invalid_op+0x32/0x40 arch/x86/kernel/traps.c:291
invalid_op+0x14/0x20 arch/x86/entry/entry_64.S:986
RIP: 0010:debug_print_object+0x160/0x250 lib/debugobjects.c:325
Code: dd e0 16 ba 85 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 bf 00 00 00 48
8b 14 dd e0 16 ba 85 48 c7 c7 c0 0c ba 85 e8 db c7 33 ff <0f> 0b 83 05 03
6e 86 05 01 48 83 c4 20 5b 5d 41 5c 41 5d c3 48 89
RSP: 0018:ffff8881d9eff710 EFLAGS: 00010086
RAX: 0000000000000000 RBX: 0000000000000003 RCX: 0000000000000000
RDX: 0000000000000000 RSI: ffffffff8127ef3d RDI: ffffed103b3dfed4
RBP: 0000000000000001 R08: ffff8881d9e36000 R09: ffffed103b663ed7
R10: ffffed103b663ed6 R11: ffff8881db31f6b7 R12: ffffffff86b04760
R13: ffffffff812db3c0 R14: ffffffff88f4bae8 R15: ffff8881d0e1a8c8
__debug_check_no_obj_freed lib/debugobjects.c:785 [inline]
debug_check_no_obj_freed+0x2a3/0x42e lib/debugobjects.c:817
free_pages_prepare mm/page_alloc.c:1140 [inline]
__free_pages_ok+0x215/0x1bb0 mm/page_alloc.c:1366
usbhid_disconnect+0x98/0xd0 drivers/hid/usbhid/hid-core.c:1414
usb_unbind_interface+0x1bd/0x8a0 drivers/usb/core/driver.c:423
__device_release_driver drivers/base/dd.c:1081 [inline]
device_release_driver_internal+0x404/0x4c0 drivers/base/dd.c:1112
bus_remove_device+0x2dc/0x4a0 drivers/base/bus.c:556
device_del+0x460/0xb80 drivers/base/core.c:2274
usb_disable_device+0x211/0x690 drivers/usb/core/message.c:1237
usb_disconnect+0x284/0x830 drivers/usb/core/hub.c:2199
hub_port_connect drivers/usb/core/hub.c:4949 [inline]
hub_port_connect_change drivers/usb/core/hub.c:5213 [inline]
port_event drivers/usb/core/hub.c:5359 [inline]
hub_event+0x13bd/0x3550 drivers/usb/core/hub.c:5441
process_one_work+0x905/0x1570 kernel/workqueue.c:2269
worker_thread+0x96/0xe20 kernel/workqueue.c:2415
kthread+0x30b/0x410 kernel/kthread.c:255
ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352
======================================================
---
This bug is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this bug report. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
syzbot can test patches for this bug, for details see:
https://goo.gl/tpsmEJ#testing-patches
^ permalink raw reply
* Re: [PATCH v4 1/3] mfd: mc13xxx: Add mc34708 adc support
From: Lee Jones @ 2019-07-25 12:36 UTC (permalink / raw)
To: Lukasz Majewski
Cc: linux-kernel, Dmitry Torokhov, Sascha Hauer, Enrico Weigelt,
Thomas Gleixner, Kate Stewart, linux-input
In-Reply-To: <20190717222602.2912-2-lukma@denx.de>
On Thu, 18 Jul 2019, Lukasz Majewski wrote:
> From: Sascha Hauer <s.hauer@pengutronix.de>
>
> The mc34708 has an improved adc. The older variants will always convert
> a fixed order of channels. The mc34708 can do up to eight conversions
> in arbitrary channel order. Currently this extended feature is not
> supported. We only support touchscreen conversions now, which will
> be sampled in a data format compatible to the older chips in order
> to keep the API between the mfd and the touchscreen driver.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Signed-off-by: Lukasz Majewski <lukma@denx.de>
>
> ---
> Changes for v4:
> - None
>
> Changes for v3:
> - None
>
> Changes for v2:
> - Change the return code patch when the mc13xxx ADC is performing conversion
> - Introduce new include/linux/mfd/mc34708.h header file for mc34708 specific
> defines
>
> Changes from the original patches:
> - ADC conversion functions prototypes added to fix build error
> - Adjustments to make checkpatch clean (-ENOSYS, line over 80 char)
>
> This patch applies on top of v5.2 - SHA1: 0ecfebd2b52404ae0c54a878c872bb93363ada36
> ---
> drivers/mfd/mc13xxx-core.c | 102 +++++++++++++++++++++++++++++++++++++++++++-
> drivers/mfd/mc13xxx.h | 3 ++
> include/linux/mfd/mc34708.h | 37 ++++++++++++++++
> 3 files changed, 141 insertions(+), 1 deletion(-)
> create mode 100644 include/linux/mfd/mc34708.h
>
> diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
> index 1abe7432aad8..01473d6fda21 100644
> --- a/drivers/mfd/mc13xxx-core.c
> +++ b/drivers/mfd/mc13xxx-core.c
> @@ -12,6 +12,7 @@
> #include <linux/of_device.h>
> #include <linux/platform_device.h>
> #include <linux/mfd/core.h>
> +#include <linux/mfd/mc34708.h>
>
> #include "mc13xxx.h"
>
> @@ -45,6 +46,8 @@
>
> #define MC13XXX_ADC2 45
>
> +#define MC13XXX_ADC_WORKING (1 << 0)
BIT(0) ?
> void mc13xxx_lock(struct mc13xxx *mc13xxx)
> {
> if (!mutex_trylock(&mc13xxx->lock)) {
> @@ -198,22 +201,30 @@ static void mc34708_print_revision(struct mc13xxx *mc13xxx, u32 revision)
> maskval(revision, MC34708_REVISION_FAB));
> }
>
> +static int mc13xxx_adc_conversion(struct mc13xxx *, unsigned int,
> + unsigned int, u8, bool, unsigned int *);
> +static int mc34708_adc_conversion(struct mc13xxx *, unsigned int,
> + unsigned int, u8, bool, unsigned int *);
> +
> /* These are only exported for mc13xxx-i2c and mc13xxx-spi */
> struct mc13xxx_variant mc13xxx_variant_mc13783 = {
> .name = "mc13783",
> .print_revision = mc13xxx_print_revision,
> + .adc_do_conversion = mc13xxx_adc_conversion,
> };
> EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13783);
I'd prefer to keep the call-back functions as close to zero as
possible.
It would be better to turn mc13xxx_adc_conversion() in to the catch
function choose an execution route based on some platform matching.
If you could do the same for print_revision too, that would be even
better.
--
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [RFC PATCH v2 0/4] Input: mpr121-polled: Add polled driver for MPR121
From: Michal Vokáč @ 2019-07-25 12:58 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer, Fabio Estevam,
linux-input, devicetree, linux-kernel, Pengutronix Kernel Team
In-Reply-To: <20190725085753.GA26665@penguin>
On 25. 07. 19 10:57, Dmitry Torokhov wrote:
> Hi Michal,
>
> On Tue, May 21, 2019 at 08:51:17AM +0200, Michal Vokáč wrote:
>> On 21. 05. 19 7:37, Dmitry Torokhov wrote:
>>> Hi Michal,
>>>
>>> On Fri, May 17, 2019 at 03:12:49PM +0200, Michal Vokáč wrote:
>>>> Hi,
>>>>
>>>> I have to deal with a situation where we have a custom i.MX6 based
>>>> platform in production that uses the MPR121 touchkey controller.
>>>> Unfortunately the chip is connected using only the I2C interface.
>>>> The interrupt line is not used. Back in 2015 (Linux v3.14), my
>>>> colleague modded the existing mpr121_touchkey.c driver to use polling
>>>> instead of interrupt.
>>>>
>>>> For quite some time yet I am in a process of updating the product from
>>>> the ancient Freescale v3.14 kernel to the latest mainline and pushing
>>>> any needed changes upstream. The DT files for our imx6dl-yapp4 platform
>>>> already made it into v5.1-rc.
>>>>
>>>> I rebased and updated our mpr121 patch to the latest mainline.
>>>> It is created as a separate driver, similarly to gpio_keys_polled.
>>>>
>>>> The I2C device is quite susceptible to ESD. An ESD test quite often
>>>> causes reset of the chip or some register randomly changes its value.
>>>> The [PATCH 3/4] adds a write-through register cache. With the cache
>>>> this state can be detected and the device can be re-initialied.
>>>>
>>>> The main question is: Is there any chance that such a polled driver
>>>> could be accepted? Is it correct to implement it as a separate driver
>>>> or should it be done as an option in the existing driver? I can not
>>>> really imagine how I would do that though..
>>>>
>>>> There are also certain worries that the MPR121 chip may no longer be
>>>> available in nonspecifically distant future. In case of EOL I will need
>>>> to add a polled driver for an other touchkey chip. May it be already
>>>> in mainline or a completely new one.
>>>
>>> I think that my addition of input_polled_dev was ultimately a wrong
>>> thing to do. I am looking into enabling polling mode for regular input
>>> devices as we then can enable polling mode in existing drivers.
>>
>> OK, that sounds good. Especially when one needs to switch from one chip
>> to another that is already in tree, the need for a whole new polling
>> driver is eliminated.
>
> Could you please try the patch below and see if it works for your use
> case? Note that I have not tried running it, but it compiles so it must
> be good ;)
Hi Dmitry,
Thank you very much for the patch!
I gave it a shot and it seems you forgot to add the input-poller.h file
to the patch.. it does not compile on my side :(
> Input: add support for polling to input devices
>
> From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>
> Separating "normal" and "polled" input devices was a mistake, as often we want
> to allow the very same device work on both interrupt-driven and polled mode,
> depending on the board on which the device is used.
>
> This introduces new APIs:
>
> - input_setup_polling
> - input_set_poll_interval
> - input_set_min_poll_interval
> - input_set_max_poll_interval
>
> These new APIs allow switching an input device into polled mode with sysfs
> attributes matching drivers using input_polled_dev APIs that will be eventually
> removed.
After reading this I am not really sure what else needs to be done
to test/use the poller. I suspect I need to modify the input device
driver (mpr121_touchkey.c in my case) like this:
If the interrupt gpio is not provided in DT, the device driver probe
function should:
- not request the threaded interrupt
- call input_setup_polling and provide it with poll_fn
Can the mpr_touchkey_interrupt function be used as is for this
purpose? The only problem I see is it returns IRQ_HANDLED.
- set the poll interval + min/max interval
- register the input device as usual (input_register_device)
- What about the device_init_wakeup? It does not make sense for
polling I think.
Just nitpicking - I also ran checkpatch.pl on the patch and it spits
out some warnings. I am not sure whether some of those should not
be fixed.
Thanks, Michal
>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
> drivers/input/Makefile | 2
> drivers/input/input-poller.c | 207 ++++++++++++++++++++++++++++++++++++++++++
> drivers/input/input.c | 36 ++++++-
> include/linux/input.h | 10 ++
> 4 files changed, 247 insertions(+), 8 deletions(-)
> create mode 100644 drivers/input/input-poller.c
>
> diff --git a/drivers/input/Makefile b/drivers/input/Makefile
> index 40de6a7be641..e35650930371 100644
> --- a/drivers/input/Makefile
> +++ b/drivers/input/Makefile
> @@ -6,7 +6,7 @@
> # Each configuration option enables a list of files.
>
> obj-$(CONFIG_INPUT) += input-core.o
> -input-core-y := input.o input-compat.o input-mt.o ff-core.o
> +input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o
>
> obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
> obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
> diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c
> new file mode 100644
> index 000000000000..008d6f362d60
> --- /dev/null
> +++ b/drivers/input/input-poller.c
> @@ -0,0 +1,207 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Support for polling mode for input devices.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/input.h>
> +#include <linux/jiffies.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/workqueue.h>
> +#include "input-poller.h"
> +
> +struct input_dev_poller {
> + void (*poll)(struct input_dev *dev);
> +
> + unsigned int poll_interval; /* msec */
> + unsigned int poll_interval_max; /* msec */
> + unsigned int poll_interval_min; /* msec */
> +
> + struct input_dev *input;
> + struct delayed_work work;
> +};
> +
> +static void input_dev_poller_queue_work(struct input_dev_poller *poller)
> +{
> + unsigned long delay;
> +
> + delay = msecs_to_jiffies(poller->poll_interval);
> + if (delay >= HZ)
> + delay = round_jiffies_relative(delay);
> +
> + queue_delayed_work(system_freezable_wq, &poller->work, delay);
> +}
> +
> +static void input_dev_poller_work(struct work_struct *work)
> +{
> + struct input_dev_poller *poller =
> + container_of(work, struct input_dev_poller, work.work);
> +
> + poller->poll(poller->input);
> + input_dev_poller_queue_work(poller);
> +}
> +
> +void input_dev_poller_finalize(struct input_dev_poller *poller)
> +{
> + if (!poller->poll_interval)
> + poller->poll_interval = 500;
> + if (!poller->poll_interval_max)
> + poller->poll_interval_max = poller->poll_interval;
> +}
> +
> +void input_dev_poller_start(struct input_dev_poller *poller)
> +{
> + /* Only start polling if polling is enabled */
> + if (poller->poll_interval > 0) {
> + poller->poll(poller->input);
> + input_dev_poller_queue_work(poller);
> + }
> +}
> +
> +void input_dev_poller_stop(struct input_dev_poller *poller)
> +{
> + cancel_delayed_work_sync(&poller->work);
> +}
> +
> +int input_setup_polling(struct input_dev *dev,
> + void (*poll_fn)(struct input_dev *dev))
> +{
> + struct input_dev_poller *poller;
> +
> + poller = kzalloc(sizeof(*poller), GFP_KERNEL);
> + if (!poller) {
> + dev_err(dev->dev.parent ?: &dev->dev,
> + "%s: unable to allocate poller structure\n", __func__);
> + return -ENOMEM;
> + }
> +
> + INIT_DELAYED_WORK(&poller->work, input_dev_poller_work);
> + poller->poll = poll_fn;
> +
> + dev->poller = poller;
> + return 0;
> +}
> +EXPORT_SYMBOL(input_setup_polling);
> +
> +static bool input_dev_ensure_poller(struct input_dev *dev)
> +{
> + if (!dev->poller) {
> + dev_err(dev->dev.parent ?: &dev->dev,
> + "poller structure has not been set up\n");
> + return false;
> + }
> +
> + return true;
> +}
> +
> +void input_set_poll_interval(struct input_dev *dev, unsigned int interval)
> +{
> + if (input_dev_ensure_poller(dev))
> + dev->poller->poll_interval = interval;
> +}
> +EXPORT_SYMBOL(input_set_poll_interval);
> +
> +void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval)
> +{
> + if (input_dev_ensure_poller(dev))
> + dev->poller->poll_interval_min = interval;
> +}
> +EXPORT_SYMBOL(input_set_min_poll_interval);
> +
> +void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval)
> +{
> + if (input_dev_ensure_poller(dev))
> + dev->poller->poll_interval_max = interval;
> +}
> +EXPORT_SYMBOL(input_set_max_poll_interval);
> +
> +/* SYSFS interface */
> +
> +static ssize_t input_dev_get_poll_interval(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct input_dev *input = to_input_dev(dev);
> +
> + return sprintf(buf, "%d\n", input->poller->poll_interval);
> +}
> +
> +static ssize_t input_dev_set_poll_interval(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct input_dev *input = to_input_dev(dev);
> + struct input_dev_poller *poller = input->poller;
> + unsigned int interval;
> + int err;
> +
> + err = kstrtouint(buf, 0, &interval);
> + if (err)
> + return err;
> +
> + if (interval < poller->poll_interval_min)
> + return -EINVAL;
> +
> + if (interval > poller->poll_interval_max)
> + return -EINVAL;
> +
> + mutex_lock(&input->mutex);
> +
> + poller->poll_interval = interval;
> +
> + if (input->users) {
> + cancel_delayed_work_sync(&poller->work);
> + if (poller->poll_interval > 0)
> + input_dev_poller_queue_work(poller);
> + }
> +
> + mutex_unlock(&input->mutex);
> +
> + return count;
> +}
> +
> +static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR,
> + input_dev_get_poll_interval, input_dev_set_poll_interval);
> +
> +static ssize_t input_dev_get_poll_max(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct input_dev *input = to_input_dev(dev);
> +
> + return sprintf(buf, "%d\n", input->poller->poll_interval_max);
> +}
> +
> +static DEVICE_ATTR(max, S_IRUGO, input_dev_get_poll_max, NULL);
> +
> +static ssize_t input_dev_get_poll_min(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct input_dev *input = to_input_dev(dev);
> +
> + return sprintf(buf, "%d\n", input->poller->poll_interval_min);
> +}
> +
> +static DEVICE_ATTR(min, S_IRUGO, input_dev_get_poll_min, NULL);
> +
> +static umode_t input_poller_attrs_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + struct device *dev = kobj_to_dev(kobj);
> + struct input_dev *input = to_input_dev(dev);
> +
> + return input->poller ? attr->mode : 0;
> +}
> +
> +static struct attribute *input_poller_attrs[] = {
> + &dev_attr_poll.attr,
> + &dev_attr_max.attr,
> + &dev_attr_min.attr,
> + NULL
> +};
> +
> +struct attribute_group input_poller_attribute_group = {
> + .is_visible = input_poller_attrs_visible,
> + .attrs = input_poller_attrs,
> +};
> diff --git a/drivers/input/input.c b/drivers/input/input.c
> index 7f3c5fcb9ed6..6b87c07d5981 100644
> --- a/drivers/input/input.c
> +++ b/drivers/input/input.c
> @@ -24,6 +24,7 @@
> #include <linux/mutex.h>
> #include <linux/rcupdate.h>
> #include "input-compat.h"
> +#include "input-poller.h"
>
> MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
> MODULE_DESCRIPTION("Input core");
> @@ -603,20 +604,31 @@ int input_open_device(struct input_handle *handle)
>
> handle->open++;
>
> - if (!dev->users++ && dev->open)
> - retval = dev->open(dev);
> + if (dev->users++) {
> + /*
> + * Device is already opened, so we can exit immediately and
> + * report success.
> + */
> + goto out;
> + }
>
> - if (retval) {
> - dev->users--;
> - if (!--handle->open) {
> + if (dev->open) {
> + retval = dev->open(dev);
> + if (retval) {
> + dev->users--;
> + handle->open--;
> /*
> * Make sure we are not delivering any more events
> * through this handle
> */
> synchronize_rcu();
> + goto out;
> }
> }
>
> + if (dev->poller)
> + input_dev_poller_start(dev->poller);
> +
> out:
> mutex_unlock(&dev->mutex);
> return retval;
> @@ -655,8 +667,13 @@ void input_close_device(struct input_handle *handle)
>
> __input_release_device(handle);
>
> - if (!--dev->users && dev->close)
> - dev->close(dev);
> + if (!--dev->users) {
> + if (dev->poller)
> + input_dev_poller_stop(dev->poller);
> +
> + if (dev->close)
> + dev->close(dev);
> + }
>
> if (!--handle->open) {
> /*
> @@ -1502,6 +1519,7 @@ static const struct attribute_group *input_dev_attr_groups[] = {
> &input_dev_attr_group,
> &input_dev_id_attr_group,
> &input_dev_caps_attr_group,
> + &input_poller_attribute_group,
> NULL
> };
>
> @@ -1511,6 +1529,7 @@ static void input_dev_release(struct device *device)
>
> input_ff_destroy(dev);
> input_mt_destroy_slots(dev);
> + kfree(dev->poller);
> kfree(dev->absinfo);
> kfree(dev->vals);
> kfree(dev);
> @@ -2135,6 +2154,9 @@ int input_register_device(struct input_dev *dev)
> if (!dev->setkeycode)
> dev->setkeycode = input_default_setkeycode;
>
> + if (dev->poller)
> + input_dev_poller_finalize(dev->poller);
> +
> error = device_add(&dev->dev);
> if (error)
> goto err_free_vals;
> diff --git a/include/linux/input.h b/include/linux/input.h
> index 510e78558c10..956f32be87cc 100644
> --- a/include/linux/input.h
> +++ b/include/linux/input.h
> @@ -21,6 +21,8 @@
> #include <linux/timer.h>
> #include <linux/mod_devicetable.h>
>
> +struct input_dev_poller;
> +
> /**
> * struct input_value - input value representation
> * @type: type of value (EV_KEY, EV_ABS, etc)
> @@ -147,6 +149,8 @@ struct input_dev {
>
> struct ff_device *ff;
>
> + struct input_dev_poller *poller;
> +
> unsigned int repeat_key;
> struct timer_list timer;
>
> @@ -361,6 +365,12 @@ void input_unregister_device(struct input_dev *);
>
> void input_reset_device(struct input_dev *);
>
> +int input_setup_polling(struct input_dev *dev,
> + void (*poll_fn)(struct input_dev *dev));
> +void input_set_poll_interval(struct input_dev *dev, unsigned int interval);
> +void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval);
> +void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval);
> +
> int __must_check input_register_handler(struct input_handler *);
> void input_unregister_handler(struct input_handler *);
>
>
^ permalink raw reply
* Re: [RFC PATCH v2 0/4] Input: mpr121-polled: Add polled driver for MPR121
From: Dmitry Torokhov @ 2019-07-25 14:40 UTC (permalink / raw)
To: Michal Vokáč
Cc: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer, Fabio Estevam,
linux-input, devicetree, linux-kernel, Pengutronix Kernel Team
In-Reply-To: <ac436c3c-fa89-f777-85b2-f38adf842e10@ysoft.com>
On Thu, Jul 25, 2019 at 02:58:02PM +0200, Michal Vokáč wrote:
> On 25. 07. 19 10:57, Dmitry Torokhov wrote:
> > Hi Michal,
> >
> > On Tue, May 21, 2019 at 08:51:17AM +0200, Michal Vokáč wrote:
> > > On 21. 05. 19 7:37, Dmitry Torokhov wrote:
> > > > Hi Michal,
> > > >
> > > > On Fri, May 17, 2019 at 03:12:49PM +0200, Michal Vokáč wrote:
> > > > > Hi,
> > > > >
> > > > > I have to deal with a situation where we have a custom i.MX6 based
> > > > > platform in production that uses the MPR121 touchkey controller.
> > > > > Unfortunately the chip is connected using only the I2C interface.
> > > > > The interrupt line is not used. Back in 2015 (Linux v3.14), my
> > > > > colleague modded the existing mpr121_touchkey.c driver to use polling
> > > > > instead of interrupt.
> > > > >
> > > > > For quite some time yet I am in a process of updating the product from
> > > > > the ancient Freescale v3.14 kernel to the latest mainline and pushing
> > > > > any needed changes upstream. The DT files for our imx6dl-yapp4 platform
> > > > > already made it into v5.1-rc.
> > > > >
> > > > > I rebased and updated our mpr121 patch to the latest mainline.
> > > > > It is created as a separate driver, similarly to gpio_keys_polled.
> > > > >
> > > > > The I2C device is quite susceptible to ESD. An ESD test quite often
> > > > > causes reset of the chip or some register randomly changes its value.
> > > > > The [PATCH 3/4] adds a write-through register cache. With the cache
> > > > > this state can be detected and the device can be re-initialied.
> > > > >
> > > > > The main question is: Is there any chance that such a polled driver
> > > > > could be accepted? Is it correct to implement it as a separate driver
> > > > > or should it be done as an option in the existing driver? I can not
> > > > > really imagine how I would do that though..
> > > > >
> > > > > There are also certain worries that the MPR121 chip may no longer be
> > > > > available in nonspecifically distant future. In case of EOL I will need
> > > > > to add a polled driver for an other touchkey chip. May it be already
> > > > > in mainline or a completely new one.
> > > >
> > > > I think that my addition of input_polled_dev was ultimately a wrong
> > > > thing to do. I am looking into enabling polling mode for regular input
> > > > devices as we then can enable polling mode in existing drivers.
> > >
> > > OK, that sounds good. Especially when one needs to switch from one chip
> > > to another that is already in tree, the need for a whole new polling
> > > driver is eliminated.
> >
> > Could you please try the patch below and see if it works for your use
> > case? Note that I have not tried running it, but it compiles so it must
> > be good ;)
>
> Hi Dmitry,
> Thank you very much for the patch!
> I gave it a shot and it seems you forgot to add the input-poller.h file
> to the patch.. it does not compile on my side :(
Oops ;) Please see the updated patch below.
>
> > Input: add support for polling to input devices
> >
> > From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> >
> > Separating "normal" and "polled" input devices was a mistake, as often we want
> > to allow the very same device work on both interrupt-driven and polled mode,
> > depending on the board on which the device is used.
> >
> > This introduces new APIs:
> >
> > - input_setup_polling
> > - input_set_poll_interval
> > - input_set_min_poll_interval
> > - input_set_max_poll_interval
> >
> > These new APIs allow switching an input device into polled mode with sysfs
> > attributes matching drivers using input_polled_dev APIs that will be eventually
> > removed.
>
> After reading this I am not really sure what else needs to be done
> to test/use the poller. I suspect I need to modify the input device
> driver (mpr121_touchkey.c in my case) like this:
>
> If the interrupt gpio is not provided in DT, the device driver probe
> function should:
> - not request the threaded interrupt
> - call input_setup_polling and provide it with poll_fn
> Can the mpr_touchkey_interrupt function be used as is for this
> purpose? The only problem I see is it returns IRQ_HANDLED.
I'd factor out code suitable for polling from mpr_touchkey_interrupt()
and then do
static irqreturn_t mpr_touchkey_interrupt(...)
{
mpr_touchkey_report(...);
return IRQ_HANDLED;
}
>
> - set the poll interval + min/max interval
> - register the input device as usual (input_register_device)
Yes.
> - What about the device_init_wakeup? It does not make sense for
> polling I think.
We can either trust DT not to have the property for polled case, or add
more checks. I think we should simply trust DT. Even if it is wrong it
will not cause any issues.
>
> Just nitpicking - I also ran checkpatch.pl on the patch and it spits
> out some warnings. I am not sure whether some of those should not
> be fixed.
I think in this particular case checkpatch is full of it.
Thanks.
Input: add support for polling to input devices
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Separating "normal" and "polled" input devices was a mistake, as often we want
to allow the very same device work on both interrupt-driven and polled mode,
depending on the board on which the device is used.
This introduces new APIs:
- input_setup_polling
- input_set_poll_interval
- input_set_min_poll_interval
- input_set_max_poll_interval
These new APIs allow switching an input device into polled mode with sysfs
attributes matching drivers using input_polled_dev APIs that will be eventually
removed.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/Makefile | 2
drivers/input/input-poller.c | 207 ++++++++++++++++++++++++++++++++++++++++++
drivers/input/input-poller.h | 18 ++++
drivers/input/input.c | 36 ++++++-
include/linux/input.h | 10 ++
5 files changed, 265 insertions(+), 8 deletions(-)
create mode 100644 drivers/input/input-poller.c
create mode 100644 drivers/input/input-poller.h
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 40de6a7be641..e35650930371 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -6,7 +6,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input-core.o
-input-core-y := input.o input-compat.o input-mt.o ff-core.o
+input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c
new file mode 100644
index 000000000000..008d6f362d60
--- /dev/null
+++ b/drivers/input/input-poller.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support for polling mode for input devices.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include "input-poller.h"
+
+struct input_dev_poller {
+ void (*poll)(struct input_dev *dev);
+
+ unsigned int poll_interval; /* msec */
+ unsigned int poll_interval_max; /* msec */
+ unsigned int poll_interval_min; /* msec */
+
+ struct input_dev *input;
+ struct delayed_work work;
+};
+
+static void input_dev_poller_queue_work(struct input_dev_poller *poller)
+{
+ unsigned long delay;
+
+ delay = msecs_to_jiffies(poller->poll_interval);
+ if (delay >= HZ)
+ delay = round_jiffies_relative(delay);
+
+ queue_delayed_work(system_freezable_wq, &poller->work, delay);
+}
+
+static void input_dev_poller_work(struct work_struct *work)
+{
+ struct input_dev_poller *poller =
+ container_of(work, struct input_dev_poller, work.work);
+
+ poller->poll(poller->input);
+ input_dev_poller_queue_work(poller);
+}
+
+void input_dev_poller_finalize(struct input_dev_poller *poller)
+{
+ if (!poller->poll_interval)
+ poller->poll_interval = 500;
+ if (!poller->poll_interval_max)
+ poller->poll_interval_max = poller->poll_interval;
+}
+
+void input_dev_poller_start(struct input_dev_poller *poller)
+{
+ /* Only start polling if polling is enabled */
+ if (poller->poll_interval > 0) {
+ poller->poll(poller->input);
+ input_dev_poller_queue_work(poller);
+ }
+}
+
+void input_dev_poller_stop(struct input_dev_poller *poller)
+{
+ cancel_delayed_work_sync(&poller->work);
+}
+
+int input_setup_polling(struct input_dev *dev,
+ void (*poll_fn)(struct input_dev *dev))
+{
+ struct input_dev_poller *poller;
+
+ poller = kzalloc(sizeof(*poller), GFP_KERNEL);
+ if (!poller) {
+ dev_err(dev->dev.parent ?: &dev->dev,
+ "%s: unable to allocate poller structure\n", __func__);
+ return -ENOMEM;
+ }
+
+ INIT_DELAYED_WORK(&poller->work, input_dev_poller_work);
+ poller->poll = poll_fn;
+
+ dev->poller = poller;
+ return 0;
+}
+EXPORT_SYMBOL(input_setup_polling);
+
+static bool input_dev_ensure_poller(struct input_dev *dev)
+{
+ if (!dev->poller) {
+ dev_err(dev->dev.parent ?: &dev->dev,
+ "poller structure has not been set up\n");
+ return false;
+ }
+
+ return true;
+}
+
+void input_set_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval = interval;
+}
+EXPORT_SYMBOL(input_set_poll_interval);
+
+void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval_min = interval;
+}
+EXPORT_SYMBOL(input_set_min_poll_interval);
+
+void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval)
+{
+ if (input_dev_ensure_poller(dev))
+ dev->poller->poll_interval_max = interval;
+}
+EXPORT_SYMBOL(input_set_max_poll_interval);
+
+/* SYSFS interface */
+
+static ssize_t input_dev_get_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval);
+}
+
+static ssize_t input_dev_set_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_dev *input = to_input_dev(dev);
+ struct input_dev_poller *poller = input->poller;
+ unsigned int interval;
+ int err;
+
+ err = kstrtouint(buf, 0, &interval);
+ if (err)
+ return err;
+
+ if (interval < poller->poll_interval_min)
+ return -EINVAL;
+
+ if (interval > poller->poll_interval_max)
+ return -EINVAL;
+
+ mutex_lock(&input->mutex);
+
+ poller->poll_interval = interval;
+
+ if (input->users) {
+ cancel_delayed_work_sync(&poller->work);
+ if (poller->poll_interval > 0)
+ input_dev_poller_queue_work(poller);
+ }
+
+ mutex_unlock(&input->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(poll, S_IRUGO | S_IWUSR,
+ input_dev_get_poll_interval, input_dev_set_poll_interval);
+
+static ssize_t input_dev_get_poll_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval_max);
+}
+
+static DEVICE_ATTR(max, S_IRUGO, input_dev_get_poll_max, NULL);
+
+static ssize_t input_dev_get_poll_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct input_dev *input = to_input_dev(dev);
+
+ return sprintf(buf, "%d\n", input->poller->poll_interval_min);
+}
+
+static DEVICE_ATTR(min, S_IRUGO, input_dev_get_poll_min, NULL);
+
+static umode_t input_poller_attrs_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct input_dev *input = to_input_dev(dev);
+
+ return input->poller ? attr->mode : 0;
+}
+
+static struct attribute *input_poller_attrs[] = {
+ &dev_attr_poll.attr,
+ &dev_attr_max.attr,
+ &dev_attr_min.attr,
+ NULL
+};
+
+struct attribute_group input_poller_attribute_group = {
+ .is_visible = input_poller_attrs_visible,
+ .attrs = input_poller_attrs,
+};
diff --git a/drivers/input/input-poller.h b/drivers/input/input-poller.h
new file mode 100644
index 000000000000..e3fca0be1d32
--- /dev/null
+++ b/drivers/input/input-poller.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _INPUT_POLLER_H
+#define _INPUT_POLLER_H
+
+/*
+ * Support for polling mode for input devices.
+ */
+#include <linux/sysfs.h>
+
+struct input_dev_poller;
+
+void input_dev_poller_finalize(struct input_dev_poller *poller);
+void input_dev_poller_start(struct input_dev_poller *poller);
+void input_dev_poller_stop(struct input_dev_poller *poller);
+
+extern struct attribute_group input_poller_attribute_group;
+
+#endif /* _INPUT_POLLER_H */
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7494a0dede79..c08aa3596144 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/rcupdate.h>
#include "input-compat.h"
+#include "input-poller.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
@@ -603,20 +604,31 @@ int input_open_device(struct input_handle *handle)
handle->open++;
- if (!dev->users++ && dev->open)
- retval = dev->open(dev);
+ if (dev->users++) {
+ /*
+ * Device is already opened, so we can exit immediately and
+ * report success.
+ */
+ goto out;
+ }
- if (retval) {
- dev->users--;
- if (!--handle->open) {
+ if (dev->open) {
+ retval = dev->open(dev);
+ if (retval) {
+ dev->users--;
+ handle->open--;
/*
* Make sure we are not delivering any more events
* through this handle
*/
synchronize_rcu();
+ goto out;
}
}
+ if (dev->poller)
+ input_dev_poller_start(dev->poller);
+
out:
mutex_unlock(&dev->mutex);
return retval;
@@ -655,8 +667,13 @@ void input_close_device(struct input_handle *handle)
__input_release_device(handle);
- if (!--dev->users && dev->close)
- dev->close(dev);
+ if (!--dev->users) {
+ if (dev->poller)
+ input_dev_poller_stop(dev->poller);
+
+ if (dev->close)
+ dev->close(dev);
+ }
if (!--handle->open) {
/*
@@ -1502,6 +1519,7 @@ static const struct attribute_group *input_dev_attr_groups[] = {
&input_dev_attr_group,
&input_dev_id_attr_group,
&input_dev_caps_attr_group,
+ &input_poller_attribute_group,
NULL
};
@@ -1511,6 +1529,7 @@ static void input_dev_release(struct device *device)
input_ff_destroy(dev);
input_mt_destroy_slots(dev);
+ kfree(dev->poller);
kfree(dev->absinfo);
kfree(dev->vals);
kfree(dev);
@@ -2175,6 +2194,9 @@ int input_register_device(struct input_dev *dev)
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
+ if (dev->poller)
+ input_dev_poller_finalize(dev->poller);
+
error = device_add(&dev->dev);
if (error)
goto err_free_vals;
diff --git a/include/linux/input.h b/include/linux/input.h
index e95a439d8bd5..10346211ff15 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -21,6 +21,8 @@
#include <linux/timer.h>
#include <linux/mod_devicetable.h>
+struct input_dev_poller;
+
/**
* struct input_value - input value representation
* @type: type of value (EV_KEY, EV_ABS, etc)
@@ -156,6 +158,8 @@ struct input_dev {
struct ff_device *ff;
+ struct input_dev_poller *poller;
+
unsigned int repeat_key;
struct timer_list timer;
@@ -372,6 +376,12 @@ void input_unregister_device(struct input_dev *);
void input_reset_device(struct input_dev *);
+int input_setup_polling(struct input_dev *dev,
+ void (*poll_fn)(struct input_dev *dev));
+void input_set_poll_interval(struct input_dev *dev, unsigned int interval);
+void input_set_min_poll_interval(struct input_dev *dev, unsigned int interval);
+void input_set_max_poll_interval(struct input_dev *dev, unsigned int interval);
+
int __must_check input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
--
Dmitry
^ permalink raw reply related
* [PATCH] HID: logitech-dj: Fix check of logi_dj_recv_query_paired_devices()
From: YueHaibing @ 2019-07-25 14:57 UTC (permalink / raw)
To: jikos, benjamin.tissoires, hdegoede; +Cc: linux-kernel, linux-input, YueHaibing
In delayedwork_callback(), logi_dj_recv_query_paired_devices
may return positive value while success now, so check it
correctly.
Fixes: dbcbabf7da92 ("HID: logitech-dj: fix return value of logi_dj_recv_query_hidpp_devices")
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
drivers/hid/hid-logitech-dj.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 8cdf373..bf6b289 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -793,7 +793,7 @@ static void delayedwork_callback(struct work_struct *work)
break;
case WORKITEM_TYPE_UNKNOWN:
retval = logi_dj_recv_query_paired_devices(djrcv_dev);
- if (retval) {
+ if (retval < 0) {
hid_err(djrcv_dev->hidpp, "%s: logi_dj_recv_query_paired_devices error: %d\n",
__func__, retval);
}
--
2.7.4
^ permalink raw reply related
* Re: [Regression] 5.3-rc1: hid_llogitech_dj does not work
From: Hans de Goede @ 2019-07-25 15:50 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Linux Kernel Mailing, Benjamin Tissoires, Jiri Kosina,
linux-input
In-Reply-To: <2480108.bWkXKoXas6@kreacher>
Hi Rafael,
On 25-07-19 12:07, Rafael J. Wysocki wrote:
> Hi Hans,
>
> This is similar to a problem I reported some time ago:
>
> https://lore.kernel.org/lkml/2268131.Lc39eCoc3j@kreacher/
>
> and the device affected by it is the same.
>
> The symptom is simply that the mouse just doesn't work (no reaction). If I do
> "rmmod hid_llogitech_dj", it says "Killed", but the module does go away and
> the mouse starts to work (through the generic code I suppose), but then
> the machine hangs on attempts to suspend (nasty).
>
> Reverting all of the hid_llogitech_dj changes between 5.2 and 5.3-rc1:
>
> dbcbabf7da92 HID: logitech-dj: fix return value of logi_dj_recv_query_hidpp_devices
> 39d21e7e0043 HID: logitech-dj: make const array template static
> 423dfbc362b7 HID: logitech-dj: Add usb-id for the 27MHz MX3000 receiver
>
> helps here, but the first two don't really look like they can make any difference,
> so I guess I'm an unlucky owner of a MX3000 that doesn't quite work as expected.
>
> Any help will be appreciated. :-)
Actually we received another bug report about this and the reporter there
has come up with a patch with points to
dbcbabf7da92 HID: logitech-dj: fix return value of logi_dj_recv_query_hidpp_devices
Being the culprit, can you try just reverting that one?
I will take a closer look at this soonish.
Thank & Regards,
Hans
^ permalink raw reply
* Re: [PATCH v4 1/3] mfd: mc13xxx: Add mc34708 adc support
From: Lukasz Majewski @ 2019-07-25 16:20 UTC (permalink / raw)
To: Lee Jones
Cc: linux-kernel, Dmitry Torokhov, Sascha Hauer, Enrico Weigelt,
Thomas Gleixner, Kate Stewart, linux-input
In-Reply-To: <20190725123641.GJ23883@dell>
[-- Attachment #1: Type: text/plain, Size: 4139 bytes --]
Hi Lee,
> On Thu, 18 Jul 2019, Lukasz Majewski wrote:
>
> > From: Sascha Hauer <s.hauer@pengutronix.de>
> >
> > The mc34708 has an improved adc. The older variants will always
> > convert a fixed order of channels. The mc34708 can do up to eight
> > conversions in arbitrary channel order. Currently this extended
> > feature is not supported. We only support touchscreen conversions
> > now, which will be sampled in a data format compatible to the older
> > chips in order to keep the API between the mfd and the touchscreen
> > driver.
> >
> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> > Signed-off-by: Lukasz Majewski <lukma@denx.de>
> >
> > ---
> > Changes for v4:
> > - None
> >
> > Changes for v3:
> > - None
> >
> > Changes for v2:
> > - Change the return code patch when the mc13xxx ADC is performing
> > conversion
> > - Introduce new include/linux/mfd/mc34708.h header file for mc34708
> > specific defines
> >
> > Changes from the original patches:
> > - ADC conversion functions prototypes added to fix build error
> > - Adjustments to make checkpatch clean (-ENOSYS, line over 80 char)
> >
> > This patch applies on top of v5.2 - SHA1:
> > 0ecfebd2b52404ae0c54a878c872bb93363ada36 ---
> > drivers/mfd/mc13xxx-core.c | 102
> > +++++++++++++++++++++++++++++++++++++++++++-
> > drivers/mfd/mc13xxx.h | 3 ++ include/linux/mfd/mc34708.h |
> > 37 ++++++++++++++++ 3 files changed, 141 insertions(+), 1
> > deletion(-) create mode 100644 include/linux/mfd/mc34708.h
> >
> > diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
> > index 1abe7432aad8..01473d6fda21 100644
> > --- a/drivers/mfd/mc13xxx-core.c
> > +++ b/drivers/mfd/mc13xxx-core.c
> > @@ -12,6 +12,7 @@
> > #include <linux/of_device.h>
> > #include <linux/platform_device.h>
> > #include <linux/mfd/core.h>
> > +#include <linux/mfd/mc34708.h>
> >
> > #include "mc13xxx.h"
> >
> > @@ -45,6 +46,8 @@
> >
> > #define MC13XXX_ADC2 45
> >
> > +#define MC13XXX_ADC_WORKING (1 << 0)
>
> BIT(0) ?
The same convention - i.e. (1 << 0) is used in the rest of the file.
>
> > void mc13xxx_lock(struct mc13xxx *mc13xxx)
> > {
> > if (!mutex_trylock(&mc13xxx->lock)) {
> > @@ -198,22 +201,30 @@ static void mc34708_print_revision(struct
> > mc13xxx *mc13xxx, u32 revision) maskval(revision,
> > MC34708_REVISION_FAB)); }
> >
> > +static int mc13xxx_adc_conversion(struct mc13xxx *, unsigned int,
> > + unsigned int, u8, bool, unsigned
> > int *); +static int mc34708_adc_conversion(struct mc13xxx *,
> > unsigned int,
> > + unsigned int, u8, bool, unsigned
> > int *); +
> > /* These are only exported for mc13xxx-i2c and mc13xxx-spi */
> > struct mc13xxx_variant mc13xxx_variant_mc13783 = {
> > .name = "mc13783",
> > .print_revision = mc13xxx_print_revision,
> > + .adc_do_conversion = mc13xxx_adc_conversion,
> > };
> > EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13783);
>
> I'd prefer to keep the call-back functions as close to zero as
> possible.
If I may ask - what is wrong with having per device callback(s) ?
>
> It would be better to turn mc13xxx_adc_conversion() in to the catch
> function
Could you share any example?
> choose an execution route based on some platform matching.
>
Could you help me with giving a hint of how shall I do the "platform
matching" in this particular driver ?
The mc13xxx driver seems rather complex with SPI and I2C support and in
which the subdevices are added (e.g. rtc, adc, etc).
This particular patch just follows current driver design and fixes its
usability for mc13708 drvice.
> If you could do the same for print_revision too, that would be even
> better.
>
I would prefer to fix the driver (for mc13708) without the need to
change the working code.
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v3 1/2] platform/x86: surfacepro3_button: Fix device check
From: Andy Shevchenko @ 2019-07-25 17:57 UTC (permalink / raw)
To: Maximilian Luz
Cc: Linux Kernel Mailing List, linux-input, Platform Driver,
Dmitry Torokhov, Hans de Goede, Chen Yu, Darren Hart,
Andy Shevchenko, Benjamin Tissoires
In-Reply-To: <20190720150511.95076-2-luzmaximilian@gmail.com>
On Sat, Jul 20, 2019 at 6:05 PM Maximilian Luz <luzmaximilian@gmail.com> wrote:
>
> Do not use the surfacepro3_button driver on newer Microsoft Surface
> models, only use it on the Surface Pro 3 and 4. Newer models (5th, 6th
> and possibly future generations) use the same device as the Surface Pro
> 4 to represent their volume and power buttons (MSHW0040), but their
> actual implementation is significantly different. This patch ensures
> that the surfacepro3_button driver is only used on the Pro 3 and 4
> models, allowing a different driver to bind on other models.
>
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com>
assuming it will go thru Input subsystem.
> Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
> ---
> drivers/platform/x86/surfacepro3_button.c | 47 +++++++++++++++++++++++
> 1 file changed, 47 insertions(+)
>
> diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
> index 47c6d000465a..ec515223f654 100644
> --- a/drivers/platform/x86/surfacepro3_button.c
> +++ b/drivers/platform/x86/surfacepro3_button.c
> @@ -20,6 +20,12 @@
> #define SURFACE_BUTTON_OBJ_NAME "VGBI"
> #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
>
> +#define MSHW0040_DSM_REVISION 0x01
> +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
> +static const guid_t MSHW0040_DSM_UUID =
> + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
> + 0x49, 0x80, 0x35);
> +
> #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
>
> #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
> @@ -142,6 +148,44 @@ static int surface_button_resume(struct device *dev)
> }
> #endif
>
> +/*
> + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device
> + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right
> + * device by checking for the _DSM method and OEM Platform Revision.
> + *
> + * Returns true if the driver should bind to this device, i.e. the device is
> + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1.
> + */
> +static bool surface_button_check_MSHW0040(struct acpi_device *dev)
> +{
> + acpi_handle handle = dev->handle;
> + union acpi_object *result;
> + u64 oem_platform_rev = 0; // valid revisions are nonzero
> +
> + // get OEM platform revision
> + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
> + MSHW0040_DSM_REVISION,
> + MSHW0040_DSM_GET_OMPR,
> + NULL, ACPI_TYPE_INTEGER);
> +
> + /*
> + * If evaluating the _DSM fails, the method is not present. This means
> + * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we
> + * should use this driver. We use revision 0 indicating it is
> + * unavailable.
> + */
> +
> + if (result) {
> + oem_platform_rev = result->integer.value;
> + ACPI_FREE(result);
> + }
> +
> + dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
> +
> + return oem_platform_rev == 0;
> +}
> +
> +
> static int surface_button_add(struct acpi_device *device)
> {
> struct surface_button *button;
> @@ -154,6 +198,9 @@ static int surface_button_add(struct acpi_device *device)
> strlen(SURFACE_BUTTON_OBJ_NAME)))
> return -ENODEV;
>
> + if (!surface_button_check_MSHW0040(device))
> + return -ENODEV;
> +
> button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
> if (!button)
> return -ENOMEM;
> --
> 2.22.0
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v3 1/2] platform/x86: surfacepro3_button: Fix device check
From: Yu Chen @ 2019-07-26 1:48 UTC (permalink / raw)
To: Maximilian Luz
Cc: linux-kernel, linux-input, platform-driver-x86, Dmitry Torokhov,
Hans de Goede, Darren Hart, Andy Shevchenko, Benjamin Tissoires
In-Reply-To: <20190720150511.95076-2-luzmaximilian@gmail.com>
On Sat, Jul 20, 2019 at 05:05:10PM +0200, Maximilian Luz wrote:
> Do not use the surfacepro3_button driver on newer Microsoft Surface
> models, only use it on the Surface Pro 3 and 4. Newer models (5th, 6th
> and possibly future generations) use the same device as the Surface Pro
> 4 to represent their volume and power buttons (MSHW0040), but their
> actual implementation is significantly different. This patch ensures
> that the surfacepro3_button driver is only used on the Pro 3 and 4
> models, allowing a different driver to bind on other models.
>
> Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
> ---
Acked-by: Chen Yu <yu.c.chen@intel.com>
Thanks,
Chenyu
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox