Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/drivers/serial/sandbox.c
Line
Count
Source
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 <console.h>
13
#include <dm.h>
14
#include <os.h>
15
#include <serial.h>
16
#include <video.h>
17
#include <asm/global_data.h>
18
#include <linux/compiler.h>
19
#include <asm/serial.h>
20
#include <asm/state.h>
21
22
DECLARE_GLOBAL_DATA_PTR;
23
24
static size_t _sandbox_serial_written = 1;
25
static bool sandbox_serial_enabled = true;
26
27
size_t sandbox_serial_written(void)
28
0
{
29
0
  return _sandbox_serial_written;
30
0
}
31
32
void sandbox_serial_endisable(bool enabled)
33
0
{
34
0
  sandbox_serial_enabled = enabled;
35
0
}
36
37
/**
38
 * output_ansi_colour() - Output an ANSI colour code
39
 *
40
 * @colour: Colour to output (0-7)
41
 */
42
static void output_ansi_colour(int colour)
43
0
{
44
0
  char ansi_code[] = "\x1b[1;3Xm";
45
46
0
  ansi_code[5] = '0' + colour;
47
0
  os_write(1, ansi_code, sizeof(ansi_code) - 1);
48
0
}
49
50
static void output_ansi_reset(void)
51
0
{
52
0
  os_write(1, "\x1b[0m", 4);
53
0
}
54
55
static int sandbox_serial_probe(struct udevice *dev)
56
0
{
57
0
  struct sandbox_state *state = state_get_current();
58
0
  struct sandbox_serial_priv *priv = dev_get_priv(dev);
59
60
0
  if (state->term_raw != STATE_TERM_COOKED)
61
0
    os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
62
0
  priv->start_of_line = 0;
63
64
0
  if (state->term_raw != STATE_TERM_RAW)
65
0
    disable_ctrlc(1);
66
0
  membuf_init(&priv->buf, priv->serial_buf, sizeof(priv->serial_buf));
67
68
0
  return 0;
69
0
}
70
71
static int sandbox_serial_remove(struct udevice *dev)
72
0
{
73
0
  struct sandbox_serial_plat *plat = dev_get_plat(dev);
74
75
0
  if (plat->colour != -1)
76
0
    output_ansi_reset();
77
78
0
  return 0;
79
0
}
80
81
static void sandbox_print_color(struct udevice *dev)
82
0
{
83
0
  struct sandbox_serial_priv *priv = dev_get_priv(dev);
84
0
  struct sandbox_serial_plat *plat = dev_get_plat(dev);
85
86
  /* With of-platdata we don't real the colour correctly, so disable it */
87
0
  if (!CONFIG_IS_ENABLED(OF_PLATDATA) && priv->start_of_line &&
88
0
      plat->colour != -1) {
89
0
    priv->start_of_line = false;
90
0
    output_ansi_colour(plat->colour);
91
0
  }
92
0
}
93
94
static int sandbox_serial_putc(struct udevice *dev, const char ch)
95
0
{
96
0
  struct sandbox_serial_priv *priv = dev_get_priv(dev);
97
98
0
  if (ch == '\n')
99
0
    priv->start_of_line = true;
100
101
0
  if (sandbox_serial_enabled) {
102
0
    sandbox_print_color(dev);
103
0
    os_write(1, &ch, 1);
104
0
  }
105
0
  _sandbox_serial_written += 1;
106
0
  return 0;
107
0
}
108
109
static ssize_t sandbox_serial_puts(struct udevice *dev, const char *s,
110
           size_t len)
111
0
{
112
0
  struct sandbox_serial_priv *priv = dev_get_priv(dev);
113
0
  ssize_t ret;
114
115
0
  if (len && s[len - 1] == '\n')
116
0
    priv->start_of_line = true;
117
118
0
  if (sandbox_serial_enabled) {
119
0
    sandbox_print_color(dev);
120
0
    ret = os_write(1, s, len);
121
0
    if (ret < 0)
122
0
      return ret;
123
0
  } else {
124
0
    ret = len;
125
0
  }
126
0
  _sandbox_serial_written += ret;
127
0
  return ret;
128
0
}
129
130
static int sandbox_serial_pending(struct udevice *dev, bool input)
131
0
{
132
0
  struct sandbox_serial_priv *priv = dev_get_priv(dev);
133
0
  ssize_t count;
134
0
  char *data;
135
0
  int avail;
136
137
0
  if (!input)
138
0
    return 0;
139
140
0
  os_usleep(100);
141
0
  avail = membuf_putraw(&priv->buf, 100, false, &data);
142
0
  if (!avail)
143
0
    return 1; /* buffer full */
144
145
0
  count = os_read(0, data, avail);
146
0
  if (count > 0)
147
0
    membuf_putraw(&priv->buf, count, true, &data);
148
149
0
  return membuf_avail(&priv->buf);
150
0
}
151
152
static int sandbox_serial_getc(struct udevice *dev)
153
0
{
154
0
  struct sandbox_serial_priv *priv = dev_get_priv(dev);
155
156
0
  if (!sandbox_serial_pending(dev, true))
157
0
    return -EAGAIN; /* buffer empty */
158
159
0
  return membuf_getbyte(&priv->buf);
160
0
}
161
162
#ifdef CONFIG_DEBUG_UART_SANDBOX
163
164
#include <debug_uart.h>
165
166
static inline void _debug_uart_init(void)
167
0
{
168
0
}
169
170
static inline void _debug_uart_putc(int ch)
171
0
{
172
0
  os_putc(ch);
173
0
}
174
175
DEBUG_UART_FUNCS
176
177
#endif /* CONFIG_DEBUG_UART_SANDBOX */
178
179
static int sandbox_serial_getconfig(struct udevice *dev, uint *serial_config)
180
0
{
181
0
  uint config = SERIAL_DEFAULT_CONFIG;
182
183
0
  if (!serial_config)
184
0
    return -EINVAL;
185
186
0
  *serial_config = config;
187
188
0
  return 0;
189
0
}
190
191
static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config)
192
0
{
193
0
  u8 parity = SERIAL_GET_PARITY(serial_config);
194
0
  u8 bits = SERIAL_GET_BITS(serial_config);
195
0
  u8 stop = SERIAL_GET_STOP(serial_config);
196
197
0
  if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP ||
198
0
      parity != SERIAL_PAR_NONE)
199
0
    return -ENOTSUPP; /* not supported in driver*/
200
201
0
  return 0;
202
0
}
203
204
static int sandbox_serial_getinfo(struct udevice *dev,
205
          struct serial_device_info *serial_info)
206
0
{
207
0
  struct serial_device_info info = {
208
0
    .type = SERIAL_CHIP_UNKNOWN,
209
0
    .addr_space = SERIAL_ADDRESS_SPACE_IO,
210
0
    .addr = SERIAL_DEFAULT_ADDRESS,
211
0
    .reg_width = 1,
212
0
    .reg_offset = 0,
213
0
    .reg_shift = 0,
214
0
    .clock = SERIAL_DEFAULT_CLOCK,
215
0
  };
216
217
0
  if (!serial_info)
218
0
    return -EINVAL;
219
220
0
  *serial_info = info;
221
222
0
  return 0;
223
0
}
224
225
static const char * const ansi_colour[] = {
226
  "black", "red", "green", "yellow", "blue", "megenta", "cyan",
227
  "white",
228
};
229
230
static int sandbox_serial_of_to_plat(struct udevice *dev)
231
0
{
232
0
  struct sandbox_serial_plat *plat = dev_get_plat(dev);
233
0
  const char *colour;
234
0
  int i;
235
236
0
  if (CONFIG_IS_ENABLED(OF_PLATDATA))
237
0
    return 0;
238
0
  plat->colour = -1;
239
0
  colour = dev_read_string(dev, "sandbox,text-colour");
240
0
  if (colour) {
241
0
    for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
242
0
      if (!strcmp(colour, ansi_colour[i])) {
243
0
        plat->colour = i;
244
0
        break;
245
0
      }
246
0
    }
247
0
  }
248
249
0
  return 0;
250
0
}
251
252
static const struct dm_serial_ops sandbox_serial_ops = {
253
  .putc = sandbox_serial_putc,
254
  .puts = sandbox_serial_puts,
255
  .pending = sandbox_serial_pending,
256
  .getc = sandbox_serial_getc,
257
  .getconfig = sandbox_serial_getconfig,
258
  .setconfig = sandbox_serial_setconfig,
259
  .getinfo = sandbox_serial_getinfo,
260
};
261
262
static const struct udevice_id sandbox_serial_ids[] = {
263
  { .compatible = "sandbox,serial" },
264
  { }
265
};
266
267
U_BOOT_DRIVER(sandbox_serial) = {
268
  .name = "sandbox_serial",
269
  .id = UCLASS_SERIAL,
270
  .of_match = sandbox_serial_ids,
271
  .of_to_plat = sandbox_serial_of_to_plat,
272
  .plat_auto  = sizeof(struct sandbox_serial_plat),
273
  .priv_auto  = sizeof(struct sandbox_serial_priv),
274
  .probe = sandbox_serial_probe,
275
  .remove = sandbox_serial_remove,
276
  .ops  = &sandbox_serial_ops,
277
  .flags = DM_FLAG_PRE_RELOC,
278
};
279
280
#if CONFIG_IS_ENABLED(OF_REAL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
281
static const struct sandbox_serial_plat platdata_non_fdt = {
282
  .colour = -1,
283
};
284
285
U_BOOT_DRVINFO(serial_sandbox_non_fdt) = {
286
  .name = "sandbox_serial",
287
  .plat = &platdata_non_fdt,
288
};
289
#endif