From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752943AbdCNNs5 (ORCPT ); Tue, 14 Mar 2017 09:48:57 -0400 Received: from mail-pg0-f67.google.com ([74.125.83.67]:36855 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752609AbdCNNs0 (ORCPT ); Tue, 14 Mar 2017 09:48:26 -0400 From: Andrey Smirnov To: Rob Herring Cc: Andrey Smirnov , cphealy@gmail.com, Guenter Roeck , linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/2] serdev: Add serdev_device_write subroutine Date: Tue, 14 Mar 2017 06:48:18 -0700 Message-Id: <20170314134819.19476-2-andrew.smirnov@gmail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170314134819.19476-1-andrew.smirnov@gmail.com> References: <20170314134819.19476-1-andrew.smirnov@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add serdev_device_write() which is a blocking call allowing to transfer arbitraty amount of data (potentially exceeding amount that serdev_device_write_buf can process in a single call) Cc: cphealy@gmail.com Cc: Guenter Roeck Cc: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Andrey Smirnov --- drivers/tty/serdev/core.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/serdev.h | 23 +++++++++++++++++------ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index f4c6c90..759e834 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -128,6 +128,41 @@ 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) +{ + int ret = count; + + if (serdev->ops->write_wakeup) + return -EINVAL; + + mutex_lock(&serdev->write_lock); + + for (;;) { + size_t chunk; + + reinit_completion(&serdev->write_wakeup); + + chunk = serdev_device_write_buf(serdev, buf, count); + if (chunk < 0) { + ret = chunk; + goto done; + } + + buf += chunk; + count -= chunk; + + if (!count) + break; + + wait_for_completion(&serdev->write_wakeup); + } +done: + mutex_unlock(&serdev->write_lock); + return ret; +} +EXPORT_SYMBOL_GPL(serdev_device_write); + void serdev_device_write_flush(struct serdev_device *serdev) { struct serdev_controller *ctrl = serdev->ctrl; @@ -232,6 +267,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_wakeup); + mutex_init(&serdev->write_lock); return serdev; } EXPORT_SYMBOL_GPL(serdev_device_alloc); diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 5176cdc..8f7aa35 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -35,16 +35,19 @@ struct serdev_device_ops { /** * struct serdev_device - Basic representation of an serdev device - * @dev: Driver model representation of the device. - * @nr: Device number on serdev bus. - * @ctrl: serdev controller managing this device. - * @ops: Device operations. + * @dev: Driver model representation of the device. + * @nr: Device number on serdev bus. + * @ctrl: serdev controller managing this device. + * @ops: Device operations. + * @write_wakeup Completion used by serdev_device_write internally */ struct serdev_device { struct device dev; int nr; struct serdev_controller *ctrl; const struct serdev_device_ops *ops; + struct completion write_wakeup; + struct mutex write_lock; }; static inline struct serdev_device *to_serdev_device(struct device *d) @@ -162,10 +165,13 @@ static inline void serdev_controller_write_wakeup(struct serdev_controller *ctrl { struct serdev_device *serdev = ctrl->serdev; - if (!serdev || !serdev->ops->write_wakeup) + if (!serdev) return; - serdev->ops->write_wakeup(serdev); + if (serdev->ops->write_wakeup) + serdev->ops->write_wakeup(serdev); + else + complete(&serdev->write_wakeup); } static inline int serdev_controller_receive_buf(struct serdev_controller *ctrl, @@ -187,6 +193,7 @@ void serdev_device_close(struct serdev_device *); unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int); void serdev_device_set_flow_control(struct serdev_device *, bool); int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t); +int serdev_device_write(struct serdev_device *serdev, const unsigned char *buf, size_t count); void serdev_device_write_flush(struct serdev_device *); int serdev_device_write_room(struct serdev_device *); @@ -227,6 +234,10 @@ static inline int serdev_device_write_buf(struct serdev_device *sdev, const unsi { return -ENODEV; } +static inline int serdev_device_write(struct serdev_device *sdev, const unsigned char *buf, size_t count) +{ + return -ENODEV; +} static inline void serdev_device_write_flush(struct serdev_device *sdev) {} static inline int serdev_device_write_room(struct serdev_device *sdev) { -- 2.9.3