HID: cp2112: prevent sleeping function called from invalid context [Linux 4.19.72]

This Linux kernel change "HID: cp2112: prevent sleeping function called from invalid context" is included in the Linux 4.19.72 release. This change is authored by Benjamin Tissoires <benjamin.tissoires [at] redhat.com> on Mon Aug 12 18:04:44 2019 +0200. The commit for this change in Linux stable tree is 05d611c (patch) which is from upstream commit 2d05dba. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 2d05dba.

HID: cp2112: prevent sleeping function called from invalid context

[ Upstream commit 2d05dba2b25ecb0f8fc3a0b4eb2232da6454a47b ]

When calling request_threaded_irq() with a CP2112, the function
cp2112_gpio_irq_startup() is called in a IRQ context.

Therefore we can not sleep, and we can not call
cp2112_gpio_direction_input() there.

Move the call to cp2112_gpio_direction_input() earlier to have a working
driver.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 8 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/hid/hid-cp2112.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 271f314..6f65f52 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -1160,8 +1160,6 @@ static unsigned int cp2112_gpio_irq_startup(struct irq_data *d)

    INIT_DELAYED_WORK(&dev->gpio_poll_worker, cp2112_gpio_poll_callback);

-   cp2112_gpio_direction_input(gc, d->hwirq);
-
    if (!dev->gpio_poll) {
        dev->gpio_poll = true;
        schedule_delayed_work(&dev->gpio_poll_worker, 0);
@@ -1209,6 +1207,12 @@ static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
        return PTR_ERR(dev->desc[pin]);
    }

+   ret = cp2112_gpio_direction_input(&dev->gc, pin);
+   if (ret < 0) {
+       dev_err(dev->gc.parent, "Failed to set GPIO to input dir\n");
+       goto err_desc;
+   }
+
    ret = gpiochip_lock_as_irq(&dev->gc, pin);
    if (ret) {
        dev_err(dev->gc.parent, "Failed to lock GPIO as interrupt\n");

Leave a Reply

Your email address will not be published. Required fields are marked *