Allow the synchronous serdev_device_write() helper to be interrupted.

This is useful for cases where I/O is performed on behalf of user space
and we don't want to block indefinitely when using flow control.

Signed-off-by: Johan Hovold <jo...@kernel.org>
---
 drivers/tty/serdev/core.c | 20 ++++++++++++++------
 include/linux/serdev.h    |  2 +-
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index ee4c40336633..c7006bbb793a 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -231,7 +231,7 @@ EXPORT_SYMBOL_GPL(serdev_device_write_buf);
 
 int serdev_device_write(struct serdev_device *serdev,
                        const unsigned char *buf, size_t count,
-                       unsigned long timeout)
+                       long timeout)
 {
        struct serdev_controller *ctrl = serdev->ctrl;
        int written = 0;
@@ -254,16 +254,24 @@ int serdev_device_write(struct serdev_device *serdev,
                written += ret;
                buf += ret;
                count -= ret;
-       } while (count &&
-                (timeout = wait_for_completion_timeout(&serdev->write_comp,
-                                                       timeout)));
+
+               if (count == 0)
+                       break;
+
+               timeout = 
wait_for_completion_interruptible_timeout(&serdev->write_comp,
+                                                                   timeout);
+       } while (timeout > 0);
        mutex_unlock(&serdev->write_lock);
 
        if (ret < 0)
                return ret;
 
-       if (timeout == 0 && written == 0)
-               return -ETIMEDOUT;
+       if (timeout <= 0 && written == 0) {
+               if (timeout == -ERESTARTSYS)
+                       return -ERESTARTSYS;
+               else
+                       return -ETIMEDOUT;
+       }
 
        return written;
 }
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index f153b2c7f0cd..070bf4e92df7 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -210,7 +210,7 @@ void serdev_device_wait_until_sent(struct serdev_device *, 
long);
 int serdev_device_get_tiocm(struct serdev_device *);
 int serdev_device_set_tiocm(struct serdev_device *, int, int);
 void serdev_device_write_wakeup(struct serdev_device *);
-int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, 
unsigned long);
+int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, 
long);
 void serdev_device_write_flush(struct serdev_device *);
 int serdev_device_write_room(struct serdev_device *);
 
-- 
2.19.1

Reply via email to