uboot/drivers/serial/sandbox.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011 The Chromium OS Authors.
   4 */
   5
   6/*
   7 * This provide a test serial port. It provides an emulated serial port where
   8 * a test program and read out the serial output and inject serial input for
   9 * U-Boot.
  10 */
  11
  12#include <common.h>
  13#include <console.h>
  14#include <dm.h>
  15#include <lcd.h>
  16#include <os.h>
  17#include <serial.h>
  18#include <video.h>
  19#include <asm/global_data.h>
  20#include <linux/compiler.h>
  21#include <asm/serial.h>
  22#include <asm/state.h>
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26/**
  27 * output_ansi_colour() - Output an ANSI colour code
  28 *
  29 * @colour: Colour to output (0-7)
  30 */
  31static void output_ansi_colour(int colour)
  32{
  33        char ansi_code[] = "\x1b[1;3Xm";
  34
  35        ansi_code[5] = '0' + colour;
  36        os_write(1, ansi_code, sizeof(ansi_code) - 1);
  37}
  38
  39static void output_ansi_reset(void)
  40{
  41        os_write(1, "\x1b[0m", 4);
  42}
  43
  44static int sandbox_serial_probe(struct udevice *dev)
  45{
  46        struct sandbox_state *state = state_get_current();
  47        struct sandbox_serial_priv *priv = dev_get_priv(dev);
  48
  49        if (state->term_raw != STATE_TERM_COOKED)
  50                os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
  51        priv->start_of_line = 0;
  52
  53        if (state->term_raw != STATE_TERM_RAW)
  54                disable_ctrlc(1);
  55        membuff_init(&priv->buf, priv->serial_buf, sizeof(priv->serial_buf));
  56
  57        return 0;
  58}
  59
  60static int sandbox_serial_remove(struct udevice *dev)
  61{
  62        struct sandbox_serial_plat *plat = dev_get_plat(dev);
  63
  64        if (plat->colour != -1)
  65                output_ansi_reset();
  66
  67        return 0;
  68}
  69
  70static int sandbox_serial_putc(struct udevice *dev, const char ch)
  71{
  72        struct sandbox_serial_priv *priv = dev_get_priv(dev);
  73        struct sandbox_serial_plat *plat = dev_get_plat(dev);
  74
  75        /* With of-platdata we don't real the colour correctly, so disable it */
  76        if (!CONFIG_IS_ENABLED(OF_PLATDATA) && priv->start_of_line &&
  77            plat->colour != -1) {
  78                priv->start_of_line = false;
  79                output_ansi_colour(plat->colour);
  80        }
  81
  82        os_write(1, &ch, 1);
  83        if (ch == '\n')
  84                priv->start_of_line = true;
  85
  86        return 0;
  87}
  88
  89static int sandbox_serial_pending(struct udevice *dev, bool input)
  90{
  91        struct sandbox_serial_priv *priv = dev_get_priv(dev);
  92        ssize_t count;
  93        char *data;
  94        int avail;
  95
  96        if (!input)
  97                return 0;
  98
  99        os_usleep(100);
 100        if (IS_ENABLED(CONFIG_DM_VIDEO) && !IS_ENABLED(CONFIG_SPL_BUILD))
 101                video_sync_all();
 102        avail = membuff_putraw(&priv->buf, 100, false, &data);
 103        if (!avail)
 104                return 1;       /* buffer full */
 105
 106        count = os_read(0, data, avail);
 107        if (count > 0)
 108                membuff_putraw(&priv->buf, count, true, &data);
 109
 110        return membuff_avail(&priv->buf);
 111}
 112
 113static int sandbox_serial_getc(struct udevice *dev)
 114{
 115        struct sandbox_serial_priv *priv = dev_get_priv(dev);
 116
 117        if (!sandbox_serial_pending(dev, true))
 118                return -EAGAIN; /* buffer empty */
 119
 120        return membuff_getbyte(&priv->buf);
 121}
 122
 123#ifdef CONFIG_DEBUG_UART_SANDBOX
 124
 125#include <debug_uart.h>
 126
 127static inline void _debug_uart_init(void)
 128{
 129}
 130
 131static inline void _debug_uart_putc(int ch)
 132{
 133        os_putc(ch);
 134}
 135
 136DEBUG_UART_FUNCS
 137
 138#endif /* CONFIG_DEBUG_UART_SANDBOX */
 139
 140static int sandbox_serial_getconfig(struct udevice *dev, uint *serial_config)
 141{
 142        uint config = SERIAL_DEFAULT_CONFIG;
 143
 144        if (!serial_config)
 145                return -EINVAL;
 146
 147        *serial_config = config;
 148
 149        return 0;
 150}
 151
 152static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config)
 153{
 154        u8 parity = SERIAL_GET_PARITY(serial_config);
 155        u8 bits = SERIAL_GET_BITS(serial_config);
 156        u8 stop = SERIAL_GET_STOP(serial_config);
 157
 158        if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP ||
 159            parity != SERIAL_PAR_NONE)
 160                return -ENOTSUPP; /* not supported in driver*/
 161
 162        return 0;
 163}
 164
 165static int sandbox_serial_getinfo(struct udevice *dev,
 166                                  struct serial_device_info *serial_info)
 167{
 168        struct serial_device_info info = {
 169                .type = SERIAL_CHIP_UNKNOWN,
 170                .addr_space = SERIAL_ADDRESS_SPACE_IO,
 171                .addr = SERIAL_DEFAULT_ADDRESS,
 172                .reg_width = 1,
 173                .reg_offset = 0,
 174                .reg_shift = 0,
 175                .clock = SERIAL_DEFAULT_CLOCK,
 176        };
 177
 178        if (!serial_info)
 179                return -EINVAL;
 180
 181        *serial_info = info;
 182
 183        return 0;
 184}
 185
 186static const char * const ansi_colour[] = {
 187        "black", "red", "green", "yellow", "blue", "megenta", "cyan",
 188        "white",
 189};
 190
 191static int sandbox_serial_of_to_plat(struct udevice *dev)
 192{
 193        struct sandbox_serial_plat *plat = dev_get_plat(dev);
 194        const char *colour;
 195        int i;
 196
 197        if (CONFIG_IS_ENABLED(OF_PLATDATA))
 198                return 0;
 199        plat->colour = -1;
 200        colour = dev_read_string(dev, "sandbox,text-colour");
 201        if (colour) {
 202                for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
 203                        if (!strcmp(colour, ansi_colour[i])) {
 204                                plat->colour = i;
 205                                break;
 206                        }
 207                }
 208        }
 209
 210        return 0;
 211}
 212
 213static const struct dm_serial_ops sandbox_serial_ops = {
 214        .putc = sandbox_serial_putc,
 215        .pending = sandbox_serial_pending,
 216        .getc = sandbox_serial_getc,
 217        .getconfig = sandbox_serial_getconfig,
 218        .setconfig = sandbox_serial_setconfig,
 219        .getinfo = sandbox_serial_getinfo,
 220};
 221
 222static const struct udevice_id sandbox_serial_ids[] = {
 223        { .compatible = "sandbox,serial" },
 224        { }
 225};
 226
 227U_BOOT_DRIVER(sandbox_serial) = {
 228        .name   = "sandbox_serial",
 229        .id     = UCLASS_SERIAL,
 230        .of_match = sandbox_serial_ids,
 231        .of_to_plat = sandbox_serial_of_to_plat,
 232        .plat_auto      = sizeof(struct sandbox_serial_plat),
 233        .priv_auto      = sizeof(struct sandbox_serial_priv),
 234        .probe = sandbox_serial_probe,
 235        .remove = sandbox_serial_remove,
 236        .ops    = &sandbox_serial_ops,
 237        .flags = DM_FLAG_PRE_RELOC,
 238};
 239
 240#if CONFIG_IS_ENABLED(OF_REAL)
 241static const struct sandbox_serial_plat platdata_non_fdt = {
 242        .colour = -1,
 243};
 244
 245U_BOOT_DRVINFO(serial_sandbox_non_fdt) = {
 246        .name = "sandbox_serial",
 247        .plat = &platdata_non_fdt,
 248};
 249#endif
 250