diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2018-05-09 14:17:06 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2018-05-09 14:17:06 +0200 |
commit | cc234a70e5c237a9a81c30eb42455f466f095a73 (patch) | |
tree | d0557d8ae6d6d7420dd8d809eeaad59def97a807 /include | |
parent | 531c25972ed2bfa7e2eb3cf7ac5f7cd068b8b01b (diff) | |
parent | 0f73d8fb36ec9b51cea9f78aa66a138b4a361cd0 (diff) | |
download | barebox-cc234a70e5c237a9a81c30eb42455f466f095a73.tar.gz barebox-cc234a70e5c237a9a81c30eb42455f466f095a73.tar.xz |
Merge branch 'for-next/serdev'
Diffstat (limited to 'include')
-rw-r--r-- | include/console.h | 111 | ||||
-rw-r--r-- | include/serdev.h | 44 |
2 files changed, 155 insertions, 0 deletions
diff --git a/include/console.h b/include/console.h index 3c14e35935..673921331d 100644 --- a/include/console.h +++ b/include/console.h @@ -23,6 +23,9 @@ #include <param.h> #include <linux/list.h> #include <driver.h> +#include <serdev.h> +#include <clock.h> +#include <kfifo.h> #define CONSOLE_STDIN (1 << 0) #define CONSOLE_STDOUT (1 << 1) @@ -64,8 +67,34 @@ struct console_device { struct cdev devfs; struct cdev_operations fops; + + struct serdev_device serdev; }; +static inline struct serdev_device *to_serdev_device(struct device_d *d) +{ + struct console_device *cdev = + container_of(d, struct console_device, class_dev); + return &cdev->serdev; +} + +static inline struct console_device * +to_console_device(struct serdev_device *serdev) +{ + return container_of(serdev, struct console_device, serdev); +} + +static inline struct device_node * +console_is_serdev_node(struct console_device *cdev) +{ + struct device_d *dev = cdev->dev; + if (dev && dev->device_node && + of_get_child_count(dev->device_node)) + return dev->device_node; + + return NULL; +} + int console_register(struct console_device *cdev); int console_unregister(struct console_device *cdev); @@ -88,6 +117,88 @@ unsigned console_get_active(struct console_device *cdev); int console_set_baudrate(struct console_device *cdev, unsigned baudrate); unsigned console_get_baudrate(struct console_device *cdev); + +/** + * console_fifo_fill - fill FIFO with as much console data as possible + * + * @cdev: Console to poll for dat + * @fifo: FIFO to store the data in + */ +static inline int console_fifo_fill(struct console_device *cdev, + struct kfifo *fifo) +{ + size_t len = kfifo_len(fifo); + while (cdev->tstc(cdev) && len < fifo->size) { + kfifo_putc(fifo, (unsigned char)(cdev->getc(cdev))); + len++; + } + + return len; +} + +/** + * __console_drain - Drain console into a buffer via FIFO + * + * @__is_timeout Callback used to determine timeout condition + * @cdev Console to drain + * @fifo FIFO to use as a transient buffer + * @buf Buffer to drain console into + * @len Size of the drain buffer + * @timeout Console polling timeout in ns + * + * This function is optimized to : + * - maximize throughput (ie. read as much as is available in lower layer fifo) + * - minimize latencies (no delay or wait timeout if data available) + * - have a timeout + * This is why standard getc() is not used, and input_fifo_fill() exists. + */ +static inline int __console_drain(int (*__is_timeout)(uint64_t start_ns, + uint64_t time_offset_ns), + struct console_device *cdev, + struct kfifo *fifo, + unsigned char *buf, + int len, + uint64_t timeout) +{ + int i = 0; + uint64_t start = get_time_ns(); + + if (!len) + return -EINVAL; + + do { + /* + * To minimize wait time before we start polling Rx + * (to potentially avoid overruning Rx FIFO) we call + * console_fifo_fill first + */ + if (console_fifo_fill(cdev, fifo)) + kfifo_getc(fifo, &buf[i++]); + + } while (i < len && !__is_timeout(start, timeout)); + + return i; +} + +static inline int console_drain_non_interruptible(struct console_device *cdev, + struct kfifo *fifo, + unsigned char *buf, + int len, + uint64_t timeout) +{ + return __console_drain(is_timeout_non_interruptible, + cdev, fifo, buf, len, timeout); +} + +static inline int console_drain(struct console_device *cdev, + struct kfifo *fifo, + unsigned char *buf, + int len, + uint64_t timeout) +{ + return __console_drain(is_timeout, cdev, fifo, buf, len, timeout); +} + #ifdef CONFIG_PBL_CONSOLE void pbl_set_putc(void (*putcf)(void *ctx, int c), void *ctx); #else diff --git a/include/serdev.h b/include/serdev.h new file mode 100644 index 0000000000..f5d34f5276 --- /dev/null +++ b/include/serdev.h @@ -0,0 +1,44 @@ +#ifndef _SERDEV_H_ +#define _SERDEV_H_ + +#include <driver.h> +#include <poller.h> +#include <kfifo.h> + +/** + * struct serdev_device - Basic representation of an serdev device + * + * @dev: Corresponding device + * @fifo: Circular buffer used for console draining + * @buf: Buffer used to pass Rx data to consumers + * @poller Async poller used to poll this serdev + * @polling_interval: Async poller periodicity + * @polling_window: Duration of a single busy loop poll + * @receive_buf: Function called with data received from device; + * returns number of bytes accepted; + */ +struct serdev_device { + struct device_d *dev; + struct kfifo *fifo; + unsigned char *buf; + struct poller_async poller; + uint64_t polling_interval; + uint64_t polling_window; + + int (*receive_buf)(struct serdev_device *, const unsigned char *, + size_t); +}; + +int serdev_device_open(struct serdev_device *); +unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int); +int serdev_device_write(struct serdev_device *, const unsigned char *, + size_t, unsigned long); + +/* + * The following two functions are not a part of original Linux API + */ +int serdev_device_reader_open(struct serdev_device *, size_t); +int serdev_device_read(struct serdev_device *, unsigned char *, + size_t, unsigned long); + +#endif |