uboot/drivers/video/vidconsole-uclass.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 Google, Inc
   3 * (C) Copyright 2001-2015
   4 * DENX Software Engineering -- wd@denx.de
   5 * Compulab Ltd - http://compulab.co.il/
   6 * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
   7 *
   8 * SPDX-License-Identifier:     GPL-2.0+
   9 */
  10
  11#include <common.h>
  12#include <dm.h>
  13#include <video.h>
  14#include <video_console.h>
  15#include <video_font.h>         /* Get font data, width and height */
  16
  17/* By default we scroll by a single line */
  18#ifndef CONFIG_CONSOLE_SCROLL_LINES
  19#define CONFIG_CONSOLE_SCROLL_LINES 1
  20#endif
  21
  22int vidconsole_putc_xy(struct udevice *dev, uint x, uint y, char ch)
  23{
  24        struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  25
  26        if (!ops->putc_xy)
  27                return -ENOSYS;
  28        return ops->putc_xy(dev, x, y, ch);
  29}
  30
  31int vidconsole_move_rows(struct udevice *dev, uint rowdst, uint rowsrc,
  32                         uint count)
  33{
  34        struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  35
  36        if (!ops->move_rows)
  37                return -ENOSYS;
  38        return ops->move_rows(dev, rowdst, rowsrc, count);
  39}
  40
  41int vidconsole_set_row(struct udevice *dev, uint row, int clr)
  42{
  43        struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  44
  45        if (!ops->set_row)
  46                return -ENOSYS;
  47        return ops->set_row(dev, row, clr);
  48}
  49
  50static int vidconsole_entry_start(struct udevice *dev)
  51{
  52        struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  53
  54        if (!ops->entry_start)
  55                return -ENOSYS;
  56        return ops->entry_start(dev);
  57}
  58
  59/* Move backwards one space */
  60static int vidconsole_back(struct udevice *dev)
  61{
  62        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  63        struct vidconsole_ops *ops = vidconsole_get_ops(dev);
  64        int ret;
  65
  66        if (ops->backspace) {
  67                ret = ops->backspace(dev);
  68                if (ret != -ENOSYS)
  69                        return ret;
  70        }
  71
  72        priv->xcur_frac -= VID_TO_POS(priv->x_charsize);
  73        if (priv->xcur_frac < priv->xstart_frac) {
  74                priv->xcur_frac = (priv->cols - 1) *
  75                        VID_TO_POS(priv->x_charsize);
  76                priv->ycur -= priv->y_charsize;
  77                if (priv->ycur < 0)
  78                        priv->ycur = 0;
  79        }
  80
  81        return 0;
  82}
  83
  84/* Move to a newline, scrolling the display if necessary */
  85static void vidconsole_newline(struct udevice *dev)
  86{
  87        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
  88        struct udevice *vid_dev = dev->parent;
  89        struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
  90        const int rows = CONFIG_CONSOLE_SCROLL_LINES;
  91        int i;
  92
  93        priv->xcur_frac = priv->xstart_frac;
  94        priv->ycur += priv->y_charsize;
  95
  96        /* Check if we need to scroll the terminal */
  97        if ((priv->ycur + priv->y_charsize) / priv->y_charsize > priv->rows) {
  98                vidconsole_move_rows(dev, 0, rows, priv->rows - rows);
  99                for (i = 0; i < rows; i++)
 100                        vidconsole_set_row(dev, priv->rows - i - 1,
 101                                           vid_priv->colour_bg);
 102                priv->ycur -= rows * priv->y_charsize;
 103        }
 104        priv->last_ch = 0;
 105
 106        video_sync(dev->parent);
 107}
 108
 109int vidconsole_put_char(struct udevice *dev, char ch)
 110{
 111        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
 112        int ret;
 113
 114        switch (ch) {
 115        case '\a':
 116                /* beep */
 117                break;
 118        case '\r':
 119                priv->xcur_frac = priv->xstart_frac;
 120                break;
 121        case '\n':
 122                vidconsole_newline(dev);
 123                vidconsole_entry_start(dev);
 124                break;
 125        case '\t':      /* Tab (8 chars alignment) */
 126                priv->xcur_frac = ((priv->xcur_frac / priv->tab_width_frac)
 127                                + 1) * priv->tab_width_frac;
 128
 129                if (priv->xcur_frac >= priv->xsize_frac)
 130                        vidconsole_newline(dev);
 131                break;
 132        case '\b':
 133                vidconsole_back(dev);
 134                priv->last_ch = 0;
 135                break;
 136        default:
 137                /*
 138                 * Failure of this function normally indicates an unsupported
 139                 * colour depth. Check this and return an error to help with
 140                 * diagnosis.
 141                 */
 142                ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch);
 143                if (ret == -EAGAIN) {
 144                        vidconsole_newline(dev);
 145                        ret = vidconsole_putc_xy(dev, priv->xcur_frac,
 146                                                 priv->ycur, ch);
 147                }
 148                if (ret < 0)
 149                        return ret;
 150                priv->xcur_frac += ret;
 151                priv->last_ch = ch;
 152                if (priv->xcur_frac >= priv->xsize_frac)
 153                        vidconsole_newline(dev);
 154                break;
 155        }
 156
 157        return 0;
 158}
 159
 160static void vidconsole_putc(struct stdio_dev *sdev, const char ch)
 161{
 162        struct udevice *dev = sdev->priv;
 163
 164        vidconsole_put_char(dev, ch);
 165}
 166
 167static void vidconsole_puts(struct stdio_dev *sdev, const char *s)
 168{
 169        struct udevice *dev = sdev->priv;
 170
 171        while (*s)
 172                vidconsole_put_char(dev, *s++);
 173        video_sync(dev->parent);
 174}
 175
 176/* Set up the number of rows and colours (rotated drivers override this) */
 177static int vidconsole_pre_probe(struct udevice *dev)
 178{
 179        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
 180        struct udevice *vid = dev->parent;
 181        struct video_priv *vid_priv = dev_get_uclass_priv(vid);
 182
 183        priv->xsize_frac = VID_TO_POS(vid_priv->xsize);
 184
 185        return 0;
 186}
 187
 188/* Register the device with stdio */
 189static int vidconsole_post_probe(struct udevice *dev)
 190{
 191        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
 192        struct stdio_dev *sdev = &priv->sdev;
 193        int ret;
 194
 195        if (!priv->tab_width_frac)
 196                priv->tab_width_frac = VID_TO_POS(priv->x_charsize) * 8;
 197
 198        if (dev->seq) {
 199                snprintf(sdev->name, sizeof(sdev->name), "vidconsole%d",
 200                         dev->seq);
 201        } else {
 202                strcpy(sdev->name, "vidconsole");
 203        }
 204
 205        sdev->flags = DEV_FLAGS_OUTPUT;
 206        sdev->putc = vidconsole_putc;
 207        sdev->puts = vidconsole_puts;
 208        sdev->priv = dev;
 209        ret = stdio_register(sdev);
 210        if (ret)
 211                return ret;
 212
 213        return 0;
 214}
 215
 216UCLASS_DRIVER(vidconsole) = {
 217        .id             = UCLASS_VIDEO_CONSOLE,
 218        .name           = "vidconsole0",
 219        .pre_probe      = vidconsole_pre_probe,
 220        .post_probe     = vidconsole_post_probe,
 221        .per_device_auto_alloc_size     = sizeof(struct vidconsole_priv),
 222};
 223
 224void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row)
 225{
 226        struct vidconsole_priv *priv = dev_get_uclass_priv(dev);
 227        struct udevice *vid_dev = dev->parent;
 228        struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev);
 229
 230        priv->xcur_frac = VID_TO_POS(min_t(short, col, vid_priv->xsize - 1));
 231        priv->ycur = min_t(short, row, vid_priv->ysize - 1);
 232}
 233
 234static int do_video_setcursor(cmd_tbl_t *cmdtp, int flag, int argc,
 235                              char *const argv[])
 236{
 237        unsigned int col, row;
 238        struct udevice *dev;
 239
 240        if (argc != 3)
 241                return CMD_RET_USAGE;
 242
 243        if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
 244                return CMD_RET_FAILURE;
 245        col = simple_strtoul(argv[1], NULL, 10);
 246        row = simple_strtoul(argv[2], NULL, 10);
 247        vidconsole_position_cursor(dev, col, row);
 248
 249        return 0;
 250}
 251
 252static int do_video_puts(cmd_tbl_t *cmdtp, int flag, int argc,
 253                         char *const argv[])
 254{
 255        struct udevice *dev;
 256        const char *s;
 257
 258        if (argc != 2)
 259                return CMD_RET_USAGE;
 260
 261        if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev))
 262                return CMD_RET_FAILURE;
 263        for (s = argv[1]; *s; s++)
 264                vidconsole_put_char(dev, *s);
 265
 266        return 0;
 267}
 268
 269U_BOOT_CMD(
 270        setcurs, 3,     1,      do_video_setcursor,
 271        "set cursor position within screen",
 272        "    <col> <row> in character"
 273);
 274
 275U_BOOT_CMD(
 276        lcdputs, 2,     1,      do_video_puts,
 277        "print string on video framebuffer",
 278        "    <string>"
 279);
 280