[U-Boot] [PATCH 07/18] dm: video: Add a uclass for the text console

Simon Glass sjg at chromium.org
Tue Jan 5 17:31:03 CET 2016


The existing LCD/video interface suffers from conflating the bitmap display
with text output on that display. As a result the implementation is more
complex than it needs to me.

We can support multiple text console drivers. Create a separate uclass to
support this, with its own API.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 drivers/video/Makefile            |   2 +-
 drivers/video/vidconsole-uclass.c | 239 ++++++++++++++++++++++++++++++++++++++
 drivers/video/video-uclass.c      |  21 ++++
 include/dm/uclass-id.h            |   1 +
 include/video_console.h           | 136 ++++++++++++++++++++++
 5 files changed, 398 insertions(+), 1 deletion(-)
 create mode 100644 drivers/video/vidconsole-uclass.c
 create mode 100644 include/video_console.h

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 7192013..e82f1ae 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -7,7 +7,7 @@
 
 ifdef CONFIG_DM
 obj-$(CONFIG_DISPLAY_PORT) += dp-uclass.o
-obj-$(CONFIG_DM_VIDEO) += video-uclass.o
+obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o
 endif
 
 obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
new file mode 100644
index 0000000..ea10189
--- /dev/null
+++ b/drivers/video/vidconsole-uclass.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * (C) Copyright 2001-2015
+ * DENX Software Engineering -- wd at denx.de
+ * Compulab Ltd - http://compulab.co.il/
+ * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <video.h>
+#include <video_console.h>
+#include <video_font.h>		/* Get font data, width and height */
+
+/* By default we scroll by a single line */
+#ifndef CONFIG_CONSOLE_SCROLL_LINES
+#define CONFIG_CONSOLE_SCROLL_LINES 1
+#endif
+
+int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch)
+{
+	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+
+	if (!ops->putc_xy)
+		return -ENOSYS;
+	return ops->putc_xy(dev, x, y, ch);
+}
+
+int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
+			 uint count)
+{
+	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+
+	if (!ops->move_rows)
+		return -ENOSYS;
+	return ops->move_rows(dev, rowdst, rowsrc, count);
+}
+
+int vidconsole_set_row(struct udevice *dev, uint row, int clr)
+{
+	struct vidconsole_ops *ops = vidconsole_get_ops(dev);
+
+	if (!ops->set_row)
+		return -ENOSYS;
+	return ops->set_row(dev, row, clr);
+}
+
+/* Move backwards one space */
+static void vidconsole_back(struct udevice *dev)
+{
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
+	if (--priv->curr_col < 0) {
+		priv->curr_col = priv->cols - 1;
+		if (--priv->curr_row < 0)
+			priv->curr_row = 0;
+	}
+
+	vidconsole_putc_xy(dev, priv->curr_col * VIDEO_FONT_WIDTH,
+			   priv->curr_row * VIDEO_FONT_HEIGHT, ' ');
+}
+
+/* Move to a newline, scrolling the display if necessary */
+static void vidconsole_newline(struct udevice *dev)
+{
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+	struct udevice *vid_dev = dev->parent;
+	struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
+	const int rows = CONFIG_CONSOLE_SCROLL_LINES;
+	int i;
+
+	priv->curr_col = 0;
+
+	/* Check if we need to scroll the terminal */
+	if (++priv->curr_row >= priv->rows) {
+		vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
+		for (i = 0; i < rows; i++)
+			vidconsole_set_row(dev, priv->rows - i - 1,
+					   vid_priv->colour_bg);
+		priv->curr_row -= rows;
+	}
+	video_sync(dev->parent);
+}
+
+int vidconsole_put_char(struct udevice *dev, char ch)
+{
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+	int ret;
+
+	switch (ch) {
+	case '\r':
+		priv->curr_col = 0;
+		break;
+	case '\n':
+		vidconsole_newline(dev);
+		break;
+	case '\t':	/* Tab (8 chars alignment) */
+		priv->curr_col +=  8;
+		priv->curr_col &= ~7;
+
+		if (priv->curr_col >= priv->cols)
+			vidconsole_newline(dev);
+		break;
+	case '\b':
+		vidconsole_back(dev);
+		break;
+	default:
+		/*
+		 * Failure of this function normally indicates an unsupported
+		 * colour depth. Check this and return an error to help with
+		 * diagnosis.
+		 */
+		ret = vidconsole_putc_xy(dev,
+					 priv->curr_col * VIDEO_FONT_WIDTH,
+					 priv->curr_row * VIDEO_FONT_HEIGHT,
+					 ch);
+		if (ret)
+			return ret;
+		if (++priv->curr_col >= priv->cols)
+			vidconsole_newline(dev);
+		break;
+	}
+
+	return 0;
+}
+
+static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
+{
+	struct udevice *dev = sdev->priv;
+
+	vidconsole_put_char(dev, ch);
+}
+
+static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
+{
+	struct udevice *dev = sdev->priv;
+
+	while (*s)
+		vidconsole_put_char(dev, *s++);
+}
+
+/* Set up the number of rows and colours (rotated drivers override this) */
+static int vidconsole_pre_probe(struct udevice *dev)
+{
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+	struct udevice *vid = dev->parent;
+	struct video_priv *vid_priv = dev_get_uclass_priv(vid);
+
+	priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT;
+	priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH;
+
+	return 0;
+}
+
+/* Register the device with stdio */
+static int vidconsole_post_probe(struct udevice *dev)
+{
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+	struct stdio_dev *sdev = &priv->sdev;
+	int ret;
+
+	strlcpy(sdev->name, dev->name, sizeof(sdev->name));
+	sdev->flags = DEV_FLAGS_OUTPUT;
+	sdev->putc = vidconsole_putc;
+	sdev->puts = vidconsole_puts;
+	sdev->priv = dev;
+	ret = stdio_register(sdev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+UCLASS_DRIVER(vidconsole) = {
+	.id		= UCLASS_VIDEO_CONSOLE,
+	.name		= "vidconsole0",
+	.pre_probe	= vidconsole_pre_probe,
+	.post_probe	= vidconsole_post_probe,
+	.per_device_auto_alloc_size	= sizeof(struct vidconsole_priv),
+};
+
+void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
+{
+	struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
+
+	priv->curr_col = min_t(short, col, priv->cols - 1);
+	priv->curr_row = min_t(short, row, priv->rows - 1);
+}
+
+static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
+			      char *const argv[])
+{
+	unsigned int col, row;
+	struct udevice *dev;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
+	if (!dev)
+		return CMD_RET_FAILURE;
+	col = simple_strtoul(argv[1], NULL, 10);
+	row = simple_strtoul(argv[2], NULL, 10);
+	vidconsole_position_cursor(dev, col, row);
+
+	return 0;
+}
+
+static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	struct udevice *dev;
+	const char *s;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	uclass_first_device(UCLASS_VIDEO_CONSOLE, &dev);
+	if (!dev)
+		return CMD_RET_FAILURE;
+	for (s = argv[1]; *s; s++)
+		vidconsole_put_char(dev, *s);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	setcurs, 3,	1,	do_video_setcursor,
+	"set cursor position within screen",
+	"    <col> <row> in character"
+);
+
+U_BOOT_CMD(
+	lcdputs, 2,	1,	do_video_puts,
+	"print string on video framebuffer",
+	"    <string>"
+);
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index 1615889..63d0d9d 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -189,6 +189,27 @@ static int video_post_probe(struct udevice *dev)
 #endif
 	video_clear(dev);
 
+	/*
+	 * Create a text console devices. For now we always do this, although
+	 * it might be useful to support only bitmap drawing on the device
+	 * for boards that don't need to display text.
+	 */
+	snprintf(name, sizeof(name), "%s.vidconsole", dev->name);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot);
+	ret = device_bind_driver(dev, drv, str, &cons);
+	if (ret) {
+		debug("%s: Cannot bind console driver\n", __func__);
+		return ret;
+	}
+	ret = device_probe(cons);
+	if (ret) {
+		debug("%s: Cannot probe console driver\n", __func__);
+		return ret;
+	}
+
 	return 0;
 };
 
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 3934375..a0a3a79 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -68,6 +68,7 @@ enum uclass_id {
 	UCLASS_USB_HUB,		/* USB hub */
 	UCLASS_VIDEO,		/* Video or LCD device */
 	UCLASS_VIDEO_BRIDGE,	/* Video bridge, e.g. DisplayPort to LVDS */
+	UCLASS_VIDEO_CONSOLE,	/* Text console driver for video device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/video_console.h b/include/video_console.h
new file mode 100644
index 0000000..d4acbc8
--- /dev/null
+++ b/include/video_console.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __video_console_h
+#define __video_console_h
+
+/**
+ * struct vidconsole_priv - uclass-private data about a console device
+ *
+ * @sdev:	stdio device, acting as an output sink
+ * @curr_col:	Current text column (0=left)
+ * @curr_row:	Current row (0=top)
+ * @rows:	Number of text rows
+ * @cols:	Number of text columns
+ */
+struct vidconsole_priv {
+	struct stdio_dev sdev;
+	int curr_col;
+	int curr_row;
+	int rows;
+	int cols;
+};
+
+/**
+ * struct vidconsole_ops - Video console operations
+ *
+ * These operations work on either an absolute console position (measured
+ * in pixels) or a text row number (measured in rows, where each row consists
+ * of an entire line of text - typically 16 pixels).
+ */
+struct vidconsole_ops {
+	/**
+	 * putc_xy() - write a single character to a position
+	 *
+	 * @dev:	Device to write to
+	 * @x:		Pixel X position (0=left-most pixel)
+	 * @y:		Pixel Y position (0=top-most pixel)
+	 * @ch:		Character to write
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*putc_xy)(struct udevice *dev, uint x, uint y, char ch);
+
+	/**
+	 * move_rows() - Move text rows from one place to another
+	 *
+	 * @dev:	Device to adjust
+	 * @rowdst:	Destination text row (0=top)
+	 * @rowsrc:	Source start text row
+	 * @count:	Number of text rows to move
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*move_rows)(struct udevice *dev, uint rowdst, uint rowsrc,
+			  uint count);
+
+	/**
+	 * set_row() - Set the colour of a text row
+	 *
+	 * Every pixel contained within the text row is adjusted
+	 *
+	 * @dev:	Device to adjust
+	 * @row:	Text row to adjust (0=top)
+	 * @clr:	Raw colour (pixel value) to write to each pixel
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*set_row)(struct udevice *dev, uint row, int clr);
+};
+
+/* Get a pointer to the driver operations for a video console device */
+#define vidconsole_get_ops(dev)  ((struct vidconsole_ops *)(dev)->driver->ops)
+
+/**
+ * vidconsole_putc_xy() - write a single character to a position
+ *
+ * @dev:	Device to write to
+ * @x:		Pixel X position (0=left-most pixel)
+ * @y:		Pixel Y position (0=top-most pixel)
+ * @ch:		Character to write
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch);
+
+/**
+ * vidconsole_move_rows() - Move text rows from one place to another
+ *
+ * @dev:	Device to adjust
+ * @rowdst:	Destination text row (0=top)
+ * @rowsrc:	Source start text row
+ * @count:	Number of text rows to move
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
+			 uint count);
+
+/**
+ * vidconsole_set_row() - Set the colour of a text row
+ *
+ * Every pixel contained within the text row is adjusted
+ *
+ * @dev:	Device to adjust
+ * @row:	Text row to adjust (0=top)
+ * @clr:	Raw colour (pixel value) to write to each pixel
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_set_row(struct udevice *dev, uint row, int clr);
+
+/**
+ * vidconsole_put_char() - Output a character to the current console position
+ *
+ * Outputs a character to the console and advances the cursor. This function
+ * handles wrapping to new lines and scrolling the console. Special
+ * characters are handled also: \n, \r, \n and \t.
+ *
+ * The device always starts withthe cursor at position 0,0 (top left). It
+ * can be adjusted manually using vidconsole_position_cursor().
+ *
+ * @dev:	Device to adjust
+ * @ch:		Character to write
+ * @return 0 if OK, -ve on error
+ */
+int vidconsole_put_char(struct udevice *dev, char ch);
+
+/**
+ * vidconsole_position_cursor() - Move the text cursor
+ *
+ * @dev:	Device to adjust
+ * @col:	New cursor text column
+ * @row:	New cursor text row
+ * @return 0 if OK, -ve on error
+ */
+void vidconsole_position_cursor(struct udevice *dev, unsigned col,
+				unsigned row);
+
+#endif
-- 
2.6.0.rc2.230.g3dd15c0



More information about the U-Boot mailing list