summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-05-09 14:17:06 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2018-05-09 14:17:06 +0200
commitcc234a70e5c237a9a81c30eb42455f466f095a73 (patch)
treed0557d8ae6d6d7420dd8d809eeaad59def97a807 /include
parent531c25972ed2bfa7e2eb3cf7ac5f7cd068b8b01b (diff)
parent0f73d8fb36ec9b51cea9f78aa66a138b4a361cd0 (diff)
downloadbarebox-cc234a70e5c237a9a81c30eb42455f466f095a73.tar.gz
barebox-cc234a70e5c237a9a81c30eb42455f466f095a73.tar.xz
Merge branch 'for-next/serdev'
Diffstat (limited to 'include')
-rw-r--r--include/console.h111
-rw-r--r--include/serdev.h44
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