diff options
Diffstat (limited to 'drivers/tty/serdev/core.c')
-rw-r--r-- | drivers/tty/serdev/core.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 1c4829a56351..f71b47334149 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -116,6 +116,12 @@ void serdev_device_close(struct serdev_device *serdev) } EXPORT_SYMBOL_GPL(serdev_device_close); +void serdev_device_write_wakeup(struct serdev_device *serdev) +{ + complete(&serdev->write_comp); +} +EXPORT_SYMBOL_GPL(serdev_device_write_wakeup); + int serdev_device_write_buf(struct serdev_device *serdev, const unsigned char *buf, size_t count) { @@ -128,6 +134,36 @@ int serdev_device_write_buf(struct serdev_device *serdev, } 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) +{ + struct serdev_controller *ctrl = serdev->ctrl; + int ret; + + if (!ctrl || !ctrl->ops->write_buf || + (timeout && !serdev->ops->write_wakeup)) + return -EINVAL; + + mutex_lock(&serdev->write_lock); + do { + reinit_completion(&serdev->write_comp); + + ret = ctrl->ops->write_buf(ctrl, buf, count); + if (ret < 0) + break; + + buf += ret; + count -= ret; + + } while (count && + (timeout = wait_for_completion_timeout(&serdev->write_comp, + timeout))); + mutex_unlock(&serdev->write_lock); + return ret < 0 ? ret : (count ? -ETIMEDOUT : 0); +} +EXPORT_SYMBOL_GPL(serdev_device_write); + void serdev_device_write_flush(struct serdev_device *serdev) { struct serdev_controller *ctrl = serdev->ctrl; @@ -262,6 +298,8 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl) serdev->dev.parent = &ctrl->dev; serdev->dev.bus = &serdev_bus_type; serdev->dev.type = &serdev_device_type; + init_completion(&serdev->write_comp); + mutex_init(&serdev->write_lock); return serdev; } EXPORT_SYMBOL_GPL(serdev_device_alloc); |