xref: /OK3568_Linux_fs/u-boot/drivers/serial/sandbox.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2011 The Chromium OS Authors.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun /*
8*4882a593Smuzhiyun  * This provide a test serial port. It provides an emulated serial port where
9*4882a593Smuzhiyun  * a test program and read out the serial output and inject serial input for
10*4882a593Smuzhiyun  * U-Boot.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <common.h>
14*4882a593Smuzhiyun #include <dm.h>
15*4882a593Smuzhiyun #include <fdtdec.h>
16*4882a593Smuzhiyun #include <lcd.h>
17*4882a593Smuzhiyun #include <os.h>
18*4882a593Smuzhiyun #include <serial.h>
19*4882a593Smuzhiyun #include <video.h>
20*4882a593Smuzhiyun #include <linux/compiler.h>
21*4882a593Smuzhiyun #include <asm/state.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  *   serial_buf: A buffer that holds keyboard characters for the
28*4882a593Smuzhiyun  *		 Sandbox U-Boot.
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * invariants:
31*4882a593Smuzhiyun  *   serial_buf_write		 == serial_buf_read -> empty buffer
32*4882a593Smuzhiyun  *   (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun static char serial_buf[16];
35*4882a593Smuzhiyun static unsigned int serial_buf_write;
36*4882a593Smuzhiyun static unsigned int serial_buf_read;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun struct sandbox_serial_platdata {
39*4882a593Smuzhiyun 	int colour;	/* Text colour to use for output, -1 for none */
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct sandbox_serial_priv {
43*4882a593Smuzhiyun 	bool start_of_line;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /**
47*4882a593Smuzhiyun  * output_ansi_colour() - Output an ANSI colour code
48*4882a593Smuzhiyun  *
49*4882a593Smuzhiyun  * @colour: Colour to output (0-7)
50*4882a593Smuzhiyun  */
output_ansi_colour(int colour)51*4882a593Smuzhiyun static void output_ansi_colour(int colour)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	char ansi_code[] = "\x1b[1;3Xm";
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	ansi_code[5] = '0' + colour;
56*4882a593Smuzhiyun 	os_write(1, ansi_code, sizeof(ansi_code) - 1);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
output_ansi_reset(void)59*4882a593Smuzhiyun static void output_ansi_reset(void)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	os_write(1, "\x1b[0m", 4);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
sandbox_serial_probe(struct udevice * dev)64*4882a593Smuzhiyun static int sandbox_serial_probe(struct udevice *dev)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct sandbox_state *state = state_get_current();
67*4882a593Smuzhiyun 	struct sandbox_serial_priv *priv = dev_get_priv(dev);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	if (state->term_raw != STATE_TERM_COOKED)
70*4882a593Smuzhiyun 		os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
71*4882a593Smuzhiyun 	priv->start_of_line = 0;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
sandbox_serial_remove(struct udevice * dev)76*4882a593Smuzhiyun static int sandbox_serial_remove(struct udevice *dev)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	struct sandbox_serial_platdata *plat = dev->platdata;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	if (plat->colour != -1)
81*4882a593Smuzhiyun 		output_ansi_reset();
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
sandbox_serial_putc(struct udevice * dev,const char ch)86*4882a593Smuzhiyun static int sandbox_serial_putc(struct udevice *dev, const char ch)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct sandbox_serial_priv *priv = dev_get_priv(dev);
89*4882a593Smuzhiyun 	struct sandbox_serial_platdata *plat = dev->platdata;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (priv->start_of_line && plat->colour != -1) {
92*4882a593Smuzhiyun 		priv->start_of_line = false;
93*4882a593Smuzhiyun 		output_ansi_colour(plat->colour);
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	os_write(1, &ch, 1);
97*4882a593Smuzhiyun 	if (ch == '\n')
98*4882a593Smuzhiyun 		priv->start_of_line = true;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	return 0;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
increment_buffer_index(unsigned int index)103*4882a593Smuzhiyun static unsigned int increment_buffer_index(unsigned int index)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	return (index + 1) % ARRAY_SIZE(serial_buf);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
sandbox_serial_pending(struct udevice * dev,bool input)108*4882a593Smuzhiyun static int sandbox_serial_pending(struct udevice *dev, bool input)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	const unsigned int next_index =
111*4882a593Smuzhiyun 		increment_buffer_index(serial_buf_write);
112*4882a593Smuzhiyun 	ssize_t count;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	if (!input)
115*4882a593Smuzhiyun 		return 0;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	os_usleep(100);
118*4882a593Smuzhiyun #ifndef CONFIG_SPL_BUILD
119*4882a593Smuzhiyun 	video_sync_all();
120*4882a593Smuzhiyun #endif
121*4882a593Smuzhiyun 	if (next_index == serial_buf_read)
122*4882a593Smuzhiyun 		return 1;	/* buffer full */
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	count = os_read_no_block(0, &serial_buf[serial_buf_write], 1);
125*4882a593Smuzhiyun 	if (count == 1)
126*4882a593Smuzhiyun 		serial_buf_write = next_index;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	return serial_buf_write != serial_buf_read;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
sandbox_serial_getc(struct udevice * dev)131*4882a593Smuzhiyun static int sandbox_serial_getc(struct udevice *dev)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	int result;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (!sandbox_serial_pending(dev, true))
136*4882a593Smuzhiyun 		return -EAGAIN;	/* buffer empty */
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	result = serial_buf[serial_buf_read];
139*4882a593Smuzhiyun 	serial_buf_read = increment_buffer_index(serial_buf_read);
140*4882a593Smuzhiyun 	return result;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun static const char * const ansi_colour[] = {
144*4882a593Smuzhiyun 	"black", "red", "green", "yellow", "blue", "megenta", "cyan",
145*4882a593Smuzhiyun 	"white",
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun 
sandbox_serial_ofdata_to_platdata(struct udevice * dev)148*4882a593Smuzhiyun static int sandbox_serial_ofdata_to_platdata(struct udevice *dev)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	struct sandbox_serial_platdata *plat = dev->platdata;
151*4882a593Smuzhiyun 	const char *colour;
152*4882a593Smuzhiyun 	int i;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	plat->colour = -1;
155*4882a593Smuzhiyun 	colour = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
156*4882a593Smuzhiyun 			     "sandbox,text-colour", NULL);
157*4882a593Smuzhiyun 	if (colour) {
158*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
159*4882a593Smuzhiyun 			if (!strcmp(colour, ansi_colour[i])) {
160*4882a593Smuzhiyun 				plat->colour = i;
161*4882a593Smuzhiyun 				break;
162*4882a593Smuzhiyun 			}
163*4882a593Smuzhiyun 		}
164*4882a593Smuzhiyun 	}
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun static const struct dm_serial_ops sandbox_serial_ops = {
170*4882a593Smuzhiyun 	.putc = sandbox_serial_putc,
171*4882a593Smuzhiyun 	.pending = sandbox_serial_pending,
172*4882a593Smuzhiyun 	.getc = sandbox_serial_getc,
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun static const struct udevice_id sandbox_serial_ids[] = {
176*4882a593Smuzhiyun 	{ .compatible = "sandbox,serial" },
177*4882a593Smuzhiyun 	{ }
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun U_BOOT_DRIVER(serial_sandbox) = {
181*4882a593Smuzhiyun 	.name	= "serial_sandbox",
182*4882a593Smuzhiyun 	.id	= UCLASS_SERIAL,
183*4882a593Smuzhiyun 	.of_match = sandbox_serial_ids,
184*4882a593Smuzhiyun 	.ofdata_to_platdata = sandbox_serial_ofdata_to_platdata,
185*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct sandbox_serial_platdata),
186*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct sandbox_serial_priv),
187*4882a593Smuzhiyun 	.probe = sandbox_serial_probe,
188*4882a593Smuzhiyun 	.remove = sandbox_serial_remove,
189*4882a593Smuzhiyun 	.ops	= &sandbox_serial_ops,
190*4882a593Smuzhiyun 	.flags = DM_FLAG_PRE_RELOC,
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun static const struct sandbox_serial_platdata platdata_non_fdt = {
194*4882a593Smuzhiyun 	.colour = -1,
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
198*4882a593Smuzhiyun 	.name = "serial_sandbox",
199*4882a593Smuzhiyun 	.platdata = &platdata_non_fdt,
200*4882a593Smuzhiyun };
201