From c2ee90fb9ed90c3612301e2b86c05cfb3c008fde Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 12 Apr 2018 14:33:14 -0700 Subject: console: Add simplified 'serdev' framework from Linux kernel Port 'serdev' UART-slave deivce framework found in recent Linux kernels (post 4.13) in order to be able to port 'serdev' slave drivers from Linux. Signed-off-by: Andrey Smirnov Signed-off-by: Sascha Hauer --- common/serdev.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 common/serdev.c (limited to 'common/serdev.c') diff --git a/common/serdev.c b/common/serdev.c new file mode 100644 index 0000000000..32743738ed --- /dev/null +++ b/common/serdev.c @@ -0,0 +1,89 @@ + +#include +#include + +static void serdev_device_poller(void *context) +{ + struct serdev_device *serdev = context; + struct console_device *cdev = to_console_device(serdev); + unsigned char *buf = serdev->buf; + int ret, len; + + /* + * Since this callback is a part of poller infrastructure we + * want to use _non_interruptible version of the function + * below to prevent recursion from happening (regular + * console_drain will call is_timeout, which might end up + * calling this function again). + */ + len = console_drain_non_interruptible(cdev, serdev->fifo, buf, + PAGE_SIZE, + serdev->polling_window); + while (len > 0) { + ret = serdev->receive_buf(serdev, buf, len); + len -= ret; + buf += ret; + } + + if (serdev->polling_interval) { + /* + * Re-schedule ourselves in 'serdev->polling_interval' + * nanoseconds + */ + poller_call_async(&serdev->poller, + serdev->polling_interval, + serdev_device_poller, + serdev); + } +} + +int serdev_device_open(struct serdev_device *serdev) +{ + struct console_device *cdev = to_console_device(serdev); + int ret; + + if (!cdev->putc || !cdev->getc) + return -EINVAL; + + if (!serdev->polling_window) + return -EINVAL; + + serdev->buf = xzalloc(PAGE_SIZE); + serdev->fifo = kfifo_alloc(PAGE_SIZE); + if (!serdev->fifo) + return -ENOMEM; + + ret = poller_async_register(&serdev->poller); + if (ret) + return ret; + + return console_open(cdev); +} + +unsigned int serdev_device_set_baudrate(struct serdev_device *serdev, + unsigned int speed) +{ + struct console_device *cdev = to_console_device(serdev); + + if (console_set_baudrate(cdev, speed) < 0) + return 0; + + return console_get_baudrate(cdev); +} + +int serdev_device_write(struct serdev_device *serdev, const unsigned char *buf, + size_t count, unsigned long timeout) +{ + struct console_device *cdev = to_console_device(serdev); + + while (count--) + cdev->putc(cdev, *buf++); + /* + * Poll Rx once right after we just send some data in case our + * serdev device implements command/response type of a + * protocol and we need to start draining input as soon as + * possible. + */ + serdev_device_poller(serdev); + return 0; +} -- cgit v1.2.3