2 * Copyright (c) 2011 The Chromium OS Authors.
4 * SPDX-License-Identifier: GPL-2.0+
8 * This provide a test serial port. It provides an emulated serial port where
9 * a test program and read out the serial output and inject serial input for
20 #include <linux/compiler.h>
21 #include <asm/state.h>
23 DECLARE_GLOBAL_DATA_PTR
;
27 * serial_buf: A buffer that holds keyboard characters for the
31 * serial_buf_write == serial_buf_read -> empty buffer
32 * (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer
34 static char serial_buf
[16];
35 static unsigned int serial_buf_write
;
36 static unsigned int serial_buf_read
;
38 struct sandbox_serial_platdata
{
39 int colour
; /* Text colour to use for output, -1 for none */
42 struct sandbox_serial_priv
{
47 * output_ansi_colour() - Output an ANSI colour code
49 * @colour: Colour to output (0-7)
51 static void output_ansi_colour(int colour
)
53 char ansi_code
[] = "\x1b[1;3Xm";
55 ansi_code
[5] = '0' + colour
;
56 os_write(1, ansi_code
, sizeof(ansi_code
) - 1);
59 static void output_ansi_reset(void)
61 os_write(1, "\x1b[0m", 4);
64 static int sandbox_serial_probe(struct udevice
*dev
)
66 struct sandbox_state
*state
= state_get_current();
67 struct sandbox_serial_priv
*priv
= dev_get_priv(dev
);
69 if (state
->term_raw
!= STATE_TERM_COOKED
)
70 os_tty_raw(0, state
->term_raw
== STATE_TERM_RAW_WITH_SIGS
);
71 priv
->start_of_line
= 0;
76 static int sandbox_serial_remove(struct udevice
*dev
)
78 struct sandbox_serial_platdata
*plat
= dev
->platdata
;
80 if (plat
->colour
!= -1)
86 static int sandbox_serial_putc(struct udevice
*dev
, const char ch
)
88 struct sandbox_serial_priv
*priv
= dev_get_priv(dev
);
89 struct sandbox_serial_platdata
*plat
= dev
->platdata
;
91 if (priv
->start_of_line
&& plat
->colour
!= -1) {
92 priv
->start_of_line
= false;
93 output_ansi_colour(plat
->colour
);
98 priv
->start_of_line
= true;
103 static unsigned int increment_buffer_index(unsigned int index
)
105 return (index
+ 1) % ARRAY_SIZE(serial_buf
);
108 static int sandbox_serial_pending(struct udevice
*dev
, bool input
)
110 const unsigned int next_index
=
111 increment_buffer_index(serial_buf_write
);
118 #ifndef CONFIG_SPL_BUILD
121 if (next_index
== serial_buf_read
)
122 return 1; /* buffer full */
124 count
= os_read_no_block(0, &serial_buf
[serial_buf_write
], 1);
126 serial_buf_write
= next_index
;
128 return serial_buf_write
!= serial_buf_read
;
131 static int sandbox_serial_getc(struct udevice
*dev
)
135 if (!sandbox_serial_pending(dev
, true))
136 return -EAGAIN
; /* buffer empty */
138 result
= serial_buf
[serial_buf_read
];
139 serial_buf_read
= increment_buffer_index(serial_buf_read
);
143 static const char * const ansi_colour
[] = {
144 "black", "red", "green", "yellow", "blue", "megenta", "cyan",
148 static int sandbox_serial_ofdata_to_platdata(struct udevice
*dev
)
150 struct sandbox_serial_platdata
*plat
= dev
->platdata
;
155 colour
= fdt_getprop(gd
->fdt_blob
, dev_of_offset(dev
),
156 "sandbox,text-colour", NULL
);
158 for (i
= 0; i
< ARRAY_SIZE(ansi_colour
); i
++) {
159 if (!strcmp(colour
, ansi_colour
[i
])) {
169 static const struct dm_serial_ops sandbox_serial_ops
= {
170 .putc
= sandbox_serial_putc
,
171 .pending
= sandbox_serial_pending
,
172 .getc
= sandbox_serial_getc
,
175 static const struct udevice_id sandbox_serial_ids
[] = {
176 { .compatible
= "sandbox,serial" },
180 U_BOOT_DRIVER(serial_sandbox
) = {
181 .name
= "serial_sandbox",
183 .of_match
= sandbox_serial_ids
,
184 .ofdata_to_platdata
= sandbox_serial_ofdata_to_platdata
,
185 .platdata_auto_alloc_size
= sizeof(struct sandbox_serial_platdata
),
186 .priv_auto_alloc_size
= sizeof(struct sandbox_serial_priv
),
187 .probe
= sandbox_serial_probe
,
188 .remove
= sandbox_serial_remove
,
189 .ops
= &sandbox_serial_ops
,
190 .flags
= DM_FLAG_PRE_RELOC
,
193 static const struct sandbox_serial_platdata platdata_non_fdt
= {
197 U_BOOT_DEVICE(serial_sandbox_non_fdt
) = {
198 .name
= "serial_sandbox",
199 .platdata
= &platdata_non_fdt
,