blob: 10ab361d006928016ed12b309f6284c9462a9319 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenk47d1a6e2002-11-03 00:01:44 +00002/*
3 * (C) Copyright 2000
4 * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
wdenk47d1a6e2002-11-03 00:01:44 +00005 */
6
7#include <common.h>
Simon Glassa73bda42015-11-08 23:47:45 -07008#include <console.h>
Simon Glass7dd27e02015-06-23 15:38:33 -06009#include <debug_uart.h>
Simon Glass1ab16922022-07-31 12:28:48 -060010#include <display_options.h>
Simon Glass10a7fe92017-07-27 09:31:04 -060011#include <dm.h>
Simon Glass5e6201b2019-08-01 09:46:51 -060012#include <env.h>
wdenk47d1a6e2002-11-03 00:01:44 +000013#include <stdarg.h>
Jeroen Hofstee3b46b3b2014-10-08 22:57:48 +020014#include <iomux.h>
wdenk47d1a6e2002-11-03 00:01:44 +000015#include <malloc.h>
Simon Glass46aaad02017-06-15 21:37:52 -060016#include <mapmem.h>
Simon Glass3e9fd242013-11-10 10:27:01 -070017#include <os.h>
Joe Hershberger5c89d6d2012-12-11 22:16:29 -060018#include <serial.h>
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +020019#include <stdio_dev.h>
wdenk874ac262003-07-24 23:38:38 +000020#include <exports.h>
Simon Glass9d1f6192019-08-02 09:44:25 -060021#include <env_internal.h>
Andreas J. Reichel982ca462016-07-13 12:56:51 +020022#include <watchdog.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060023#include <asm/global_data.h>
Simon Glassdbd79542020-05-10 11:40:11 -060024#include <linux/delay.h>
wdenk47d1a6e2002-11-03 00:01:44 +000025
Wolfgang Denk6405a152006-03-31 18:32:53 +020026DECLARE_GLOBAL_DATA_PTR;
27
Joe Hershberger5c89d6d2012-12-11 22:16:29 -060028static int on_console(const char *name, const char *value, enum env_op op,
29 int flags)
30{
31 int console = -1;
32
33 /* Check for console redirection */
34 if (strcmp(name, "stdin") == 0)
35 console = stdin;
36 else if (strcmp(name, "stdout") == 0)
37 console = stdout;
38 else if (strcmp(name, "stderr") == 0)
39 console = stderr;
40
41 /* if not actually setting a console variable, we don't care */
42 if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0)
43 return 0;
44
45 switch (op) {
46 case env_op_create:
47 case env_op_overwrite:
48
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +010049 if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
50 if (iomux_doenv(console, value))
51 return 1;
52 } else {
53 /* Try assigning specified device */
54 if (console_assign(console, value) < 0)
55 return 1;
56 }
57
Joe Hershberger5c89d6d2012-12-11 22:16:29 -060058 return 0;
59
60 case env_op_delete:
61 if ((flags & H_FORCE) == 0)
62 printf("Can't delete \"%s\"\n", name);
63 return 1;
64
65 default:
66 return 0;
67 }
68}
69U_BOOT_ENV_CALLBACK(console, on_console);
70
Joe Hershberger03ddaba2012-12-11 22:16:30 -060071#ifdef CONFIG_SILENT_CONSOLE
72static int on_silent(const char *name, const char *value, enum env_op op,
73 int flags)
74{
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +010075 if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_SET))
76 if (flags & H_INTERACTIVE)
77 return 0;
78
79 if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_RELOC))
80 if ((flags & H_INTERACTIVE) == 0)
81 return 0;
Joe Hershberger03ddaba2012-12-11 22:16:30 -060082
83 if (value != NULL)
84 gd->flags |= GD_FLG_SILENT;
85 else
86 gd->flags &= ~GD_FLG_SILENT;
87
88 return 0;
89}
90U_BOOT_ENV_CALLBACK(silent, on_silent);
91#endif
92
Patrick Delaunayc20847f2020-12-18 12:46:45 +010093#ifdef CONFIG_CONSOLE_RECORD
94/* helper function: access to gd->console_out and gd->console_in */
95static void console_record_putc(const char c)
96{
97 if (!(gd->flags & GD_FLG_RECORD))
98 return;
Simon Glassd6ed4af2021-05-08 06:59:56 -060099 if (gd->console_out.start &&
100 !membuff_putbyte((struct membuff *)&gd->console_out, c))
101 gd->flags |= GD_FLG_RECORD_OVF;
Patrick Delaunayc20847f2020-12-18 12:46:45 +0100102}
103
104static void console_record_puts(const char *s)
105{
106 if (!(gd->flags & GD_FLG_RECORD))
107 return;
Simon Glassd6ed4af2021-05-08 06:59:56 -0600108 if (gd->console_out.start) {
109 int len = strlen(s);
110
111 if (membuff_put((struct membuff *)&gd->console_out, s, len) !=
112 len)
113 gd->flags |= GD_FLG_RECORD_OVF;
114 }
Patrick Delaunayc20847f2020-12-18 12:46:45 +0100115}
116
117static int console_record_getc(void)
118{
119 if (!(gd->flags & GD_FLG_RECORD))
120 return -1;
121 if (!gd->console_in.start)
122 return -1;
123
124 return membuff_getbyte((struct membuff *)&gd->console_in);
125}
126
127static int console_record_tstc(void)
128{
129 if (!(gd->flags & GD_FLG_RECORD))
130 return 0;
131 if (gd->console_in.start) {
132 if (membuff_peekbyte((struct membuff *)&gd->console_in) != -1)
133 return 1;
134 }
135 return 0;
136}
137#else
138static void console_record_putc(char c)
139{
140}
141
142static void console_record_puts(const char *s)
143{
144}
145
146static int console_record_getc(void)
147{
148 return -1;
149}
150
151static int console_record_tstc(void)
152{
153 return 0;
154}
155#endif
156
Simon Glassdfc25352017-01-16 07:03:26 -0700157#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
wdenk47d1a6e2002-11-03 00:01:44 +0000158/*
159 * if overwrite_console returns 1, the stdin, stderr and stdout
160 * are switched to the serial port, else the settings in the
161 * environment are used
162 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200163#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100164extern int overwrite_console(void);
165#define OVERWRITE_CONSOLE overwrite_console()
wdenk47d1a6e2002-11-03 00:01:44 +0000166#else
wdenk61c636e2005-03-31 18:42:15 +0000167#define OVERWRITE_CONSOLE 0
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200168#endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
wdenk47d1a6e2002-11-03 00:01:44 +0000169
Simon Glassdfc25352017-01-16 07:03:26 -0700170#endif /* CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */
wdenk47d1a6e2002-11-03 00:01:44 +0000171
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200172static int console_setfile(int file, struct stdio_dev * dev)
wdenk47d1a6e2002-11-03 00:01:44 +0000173{
174 int error = 0;
175
176 if (dev == NULL)
177 return -1;
178
179 switch (file) {
180 case stdin:
181 case stdout:
182 case stderr:
Andy Shevchenko2bce0212020-12-21 14:30:00 +0200183 error = console_start(file, dev);
184 if (error)
185 break;
wdenk47d1a6e2002-11-03 00:01:44 +0000186
187 /* Assign the new device (leaving the existing one started) */
188 stdio_devices[file] = dev;
189
190 /*
191 * Update monitor functions
192 * (to use the console stuff by other applications)
193 */
194 switch (file) {
195 case stdin:
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200196 gd->jt->getc = getchar;
Martin Dorwigcb2c2862015-01-26 15:22:54 -0700197 gd->jt->tstc = tstc;
wdenk47d1a6e2002-11-03 00:01:44 +0000198 break;
199 case stdout:
Martin Dorwigcb2c2862015-01-26 15:22:54 -0700200 gd->jt->putc = putc;
201 gd->jt->puts = puts;
Pali Rohár5aceb262022-09-05 11:31:17 +0200202 STDIO_DEV_ASSIGN_FLUSH(gd->jt, flush);
Martin Dorwigcb2c2862015-01-26 15:22:54 -0700203 gd->jt->printf = printf;
wdenk47d1a6e2002-11-03 00:01:44 +0000204 break;
205 }
206 break;
207
208 default: /* Invalid file ID */
209 error = -1;
210 }
211 return error;
212}
213
Simon Glass045e4b52017-07-27 09:31:03 -0600214/**
215 * console_dev_is_serial() - Check if a stdio device is a serial device
216 *
217 * @sdev: Device to check
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100218 * Return: true if this device is in the serial uclass (or for pre-driver-model,
Simon Glass10a7fe92017-07-27 09:31:04 -0600219 * whether it is called "serial".
Simon Glass045e4b52017-07-27 09:31:03 -0600220 */
221static bool console_dev_is_serial(struct stdio_dev *sdev)
222{
223 bool is_serial;
224
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100225 if (IS_ENABLED(CONFIG_DM_SERIAL) && (sdev->flags & DEV_FLAGS_DM)) {
Simon Glass10a7fe92017-07-27 09:31:04 -0600226 struct udevice *dev = sdev->priv;
227
228 is_serial = device_get_uclass_id(dev) == UCLASS_SERIAL;
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100229 } else {
230 is_serial = !strcmp(sdev->name, "serial");
231 }
Simon Glass045e4b52017-07-27 09:31:03 -0600232
233 return is_serial;
234}
235
Simon Glassdfc25352017-01-16 07:03:26 -0700236#if CONFIG_IS_ENABLED(CONSOLE_MUX)
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100237/** Console I/O multiplexing *******************************************/
238
Patrick Delaunay4e8d61f2020-12-18 12:46:46 +0100239/* tstcdev: save the last stdio device with pending characters, with tstc != 0 */
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200240static struct stdio_dev *tstcdev;
241struct stdio_dev **console_devices[MAX_FILES];
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100242int cd_count[MAX_FILES];
243
Andy Shevchenkoba69b2c2021-02-11 17:09:39 +0200244static void console_devices_set(int file, struct stdio_dev *dev)
Patrick Delaunay7c5f6ed2020-12-18 12:46:44 +0100245{
246 console_devices[file][0] = dev;
Andy Shevchenkof1a852a2021-02-11 17:09:38 +0200247 cd_count[file] = 1;
Patrick Delaunay7c5f6ed2020-12-18 12:46:44 +0100248}
249
Andy Shevchenkobdb0d4c2020-12-21 14:30:01 +0200250/**
251 * console_needs_start_stop() - check if we need to start or stop the STDIO device
252 * @file: STDIO file
253 * @sdev: STDIO device in question
254 *
255 * This function checks if we need to start or stop the stdio device used for
256 * a console. For IOMUX case it simply enforces one time start and one time
257 * stop of the device independently of how many STDIO files are using it. In
258 * other words, we start console once before first STDIO device wants it and
259 * stop after the last is gone.
260 */
261static bool console_needs_start_stop(int file, struct stdio_dev *sdev)
262{
Andy Shevchenko75039f52021-02-11 17:09:41 +0200263 int i;
Andy Shevchenkobdb0d4c2020-12-21 14:30:01 +0200264
265 for (i = 0; i < ARRAY_SIZE(cd_count); i++) {
266 if (i == file)
267 continue;
268
Andy Shevchenko75039f52021-02-11 17:09:41 +0200269 if (iomux_match_device(console_devices[i], cd_count[i], sdev) >= 0)
270 return false;
Andy Shevchenkobdb0d4c2020-12-21 14:30:01 +0200271 }
272 return true;
273}
274
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100275/*
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200276 * This depends on tstc() always being called before getchar().
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100277 * This is guaranteed to be true because this routine is called
278 * only from fgetc() which assures it.
279 * No attempt is made to demultiplex multiple input sources.
280 */
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100281static int console_getc(int file)
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100282{
283 unsigned char ret;
284
285 /* This is never called with testcdev == NULL */
Simon Glass0d1e1f72014-07-23 06:54:59 -0600286 ret = tstcdev->getc(tstcdev);
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100287 tstcdev = NULL;
288 return ret;
289}
290
Patrick Delaunay4e8d61f2020-12-18 12:46:46 +0100291/* Upper layer may have already called tstc(): check the saved result */
292static bool console_has_tstc(void)
293{
294 return !!tstcdev;
295}
296
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100297static int console_tstc(int file)
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100298{
299 int i, ret;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200300 struct stdio_dev *dev;
Joe Hershbergerc2f39542018-07-02 20:06:48 -0500301 int prev;
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100302
Joe Hershbergerc2f39542018-07-02 20:06:48 -0500303 prev = disable_ctrlc(1);
Andy Shevchenkoe29d0192021-02-11 17:09:42 +0200304 for_each_console_dev(i, file, dev) {
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100305 if (dev->tstc != NULL) {
Simon Glass0d1e1f72014-07-23 06:54:59 -0600306 ret = dev->tstc(dev);
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100307 if (ret > 0) {
308 tstcdev = dev;
Joe Hershbergerc2f39542018-07-02 20:06:48 -0500309 disable_ctrlc(prev);
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100310 return ret;
311 }
312 }
313 }
Joe Hershbergerc2f39542018-07-02 20:06:48 -0500314 disable_ctrlc(prev);
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100315
316 return 0;
317}
318
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100319static void console_putc(int file, const char c)
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100320{
321 int i;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200322 struct stdio_dev *dev;
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100323
Andy Shevchenkoe29d0192021-02-11 17:09:42 +0200324 for_each_console_dev(i, file, dev) {
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100325 if (dev->putc != NULL)
Simon Glass0d1e1f72014-07-23 06:54:59 -0600326 dev->putc(dev, c);
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100327 }
328}
329
Simon Glass66ee8172020-07-02 21:12:13 -0600330/**
331 * console_puts_select() - Output a string to all console devices
332 *
333 * @file: File number to output to (e,g, stdout, see stdio.h)
334 * @serial_only: true to output only to serial, false to output to everything
335 * else
336 * @s: String to output
337 */
338static void console_puts_select(int file, bool serial_only, const char *s)
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200339{
340 int i;
341 struct stdio_dev *dev;
342
Andy Shevchenkoe29d0192021-02-11 17:09:42 +0200343 for_each_console_dev(i, file, dev) {
344 bool is_serial = console_dev_is_serial(dev);
Simon Glass66ee8172020-07-02 21:12:13 -0600345
Simon Glass66ee8172020-07-02 21:12:13 -0600346 if (dev->puts && serial_only == is_serial)
Hans de Goedee355da02015-05-05 13:13:36 +0200347 dev->puts(dev, s);
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200348 }
349}
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200350
Simon Glass66ee8172020-07-02 21:12:13 -0600351void console_puts_select_stderr(bool serial_only, const char *s)
352{
Simon Glassc7ba6c82021-11-19 13:23:47 -0700353 if (gd->flags & GD_FLG_DEVINIT)
354 console_puts_select(stderr, serial_only, s);
Simon Glass66ee8172020-07-02 21:12:13 -0600355}
356
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100357static void console_puts(int file, const char *s)
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100358{
359 int i;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200360 struct stdio_dev *dev;
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100361
Andy Shevchenkoe29d0192021-02-11 17:09:42 +0200362 for_each_console_dev(i, file, dev) {
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100363 if (dev->puts != NULL)
Simon Glass0d1e1f72014-07-23 06:54:59 -0600364 dev->puts(dev, s);
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100365 }
366}
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100367
Pali Rohár5aceb262022-09-05 11:31:17 +0200368#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
369static void console_flush(int file)
370{
371 int i;
372 struct stdio_dev *dev;
373
374 for_each_console_dev(i, file, dev) {
375 if (dev->flush != NULL)
376 dev->flush(dev);
377 }
378}
379#endif
380
Tom Rinid30aeb12019-10-30 09:18:43 -0400381#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200382static inline void console_doenv(int file, struct stdio_dev *dev)
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100383{
384 iomux_doenv(file, dev->name);
385}
Tom Rinid30aeb12019-10-30 09:18:43 -0400386#endif
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100387#else
Patrick Delaunay7c5f6ed2020-12-18 12:46:44 +0100388
Andy Shevchenkoba69b2c2021-02-11 17:09:39 +0200389static void console_devices_set(int file, struct stdio_dev *dev)
Patrick Delaunay7c5f6ed2020-12-18 12:46:44 +0100390{
391}
392
Andy Shevchenkobdb0d4c2020-12-21 14:30:01 +0200393static inline bool console_needs_start_stop(int file, struct stdio_dev *sdev)
394{
395 return true;
396}
397
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100398static inline int console_getc(int file)
399{
Simon Glass0d1e1f72014-07-23 06:54:59 -0600400 return stdio_devices[file]->getc(stdio_devices[file]);
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100401}
402
Patrick Delaunay4e8d61f2020-12-18 12:46:46 +0100403static bool console_has_tstc(void)
404{
405 return false;
406}
407
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100408static inline int console_tstc(int file)
409{
Simon Glass0d1e1f72014-07-23 06:54:59 -0600410 return stdio_devices[file]->tstc(stdio_devices[file]);
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100411}
412
413static inline void console_putc(int file, const char c)
414{
Simon Glass0d1e1f72014-07-23 06:54:59 -0600415 stdio_devices[file]->putc(stdio_devices[file], c);
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100416}
417
Simon Glass66ee8172020-07-02 21:12:13 -0600418void console_puts_select(int file, bool serial_only, const char *s)
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200419{
Simon Glassc7ba6c82021-11-19 13:23:47 -0700420 if ((gd->flags & GD_FLG_DEVINIT) &&
421 serial_only == console_dev_is_serial(stdio_devices[file]))
Hans de Goedee355da02015-05-05 13:13:36 +0200422 stdio_devices[file]->puts(stdio_devices[file], s);
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200423}
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200424
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100425static inline void console_puts(int file, const char *s)
426{
Simon Glass0d1e1f72014-07-23 06:54:59 -0600427 stdio_devices[file]->puts(stdio_devices[file], s);
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100428}
Pali Rohár5aceb262022-09-05 11:31:17 +0200429
430#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
431static inline void console_flush(int file)
432{
433 if (stdio_devices[file]->flush)
434 stdio_devices[file]->flush(stdio_devices[file]);
435}
436#endif
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100437
Tom Rinid30aeb12019-10-30 09:18:43 -0400438#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200439static inline void console_doenv(int file, struct stdio_dev *dev)
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100440{
441 console_setfile(file, dev);
442}
Tom Rinid30aeb12019-10-30 09:18:43 -0400443#endif
Simon Glassdfc25352017-01-16 07:03:26 -0700444#endif /* CONIFIG_IS_ENABLED(CONSOLE_MUX) */
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100445
Andy Shevchenkoba69b2c2021-02-11 17:09:39 +0200446static void __maybe_unused console_setfile_and_devices(int file, struct stdio_dev *dev)
447{
448 console_setfile(file, dev);
449 console_devices_set(file, dev);
450}
451
Andy Shevchenko2bce0212020-12-21 14:30:00 +0200452int console_start(int file, struct stdio_dev *sdev)
453{
454 int error;
455
Andy Shevchenkobdb0d4c2020-12-21 14:30:01 +0200456 if (!console_needs_start_stop(file, sdev))
457 return 0;
458
Andy Shevchenko2bce0212020-12-21 14:30:00 +0200459 /* Start new device */
460 if (sdev->start) {
461 error = sdev->start(sdev);
462 /* If it's not started don't use it */
463 if (error < 0)
464 return error;
465 }
466 return 0;
467}
468
469void console_stop(int file, struct stdio_dev *sdev)
470{
Andy Shevchenkobdb0d4c2020-12-21 14:30:01 +0200471 if (!console_needs_start_stop(file, sdev))
472 return;
473
Andy Shevchenko2bce0212020-12-21 14:30:00 +0200474 if (sdev->stop)
475 sdev->stop(sdev);
476}
477
wdenk47d1a6e2002-11-03 00:01:44 +0000478/** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/
479
Wolfgang Denk318ef5c2010-06-20 17:14:14 +0200480int serial_printf(const char *fmt, ...)
wdenk47d1a6e2002-11-03 00:01:44 +0000481{
482 va_list args;
483 uint i;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200484 char printbuffer[CONFIG_SYS_PBSIZE];
wdenk47d1a6e2002-11-03 00:01:44 +0000485
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100486 va_start(args, fmt);
wdenk47d1a6e2002-11-03 00:01:44 +0000487
488 /* For this to work, printbuffer must be larger than
489 * anything we ever want to print.
490 */
Sonny Rao2813a212011-10-10 09:22:31 +0000491 i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100492 va_end(args);
wdenk47d1a6e2002-11-03 00:01:44 +0000493
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100494 serial_puts(printbuffer);
Wolfgang Denk318ef5c2010-06-20 17:14:14 +0200495 return i;
wdenk47d1a6e2002-11-03 00:01:44 +0000496}
497
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100498int fgetc(int file)
wdenk47d1a6e2002-11-03 00:01:44 +0000499{
Heinrich Schuchardt1bc421b2022-10-22 11:32:34 +0200500 if ((unsigned int)file < MAX_FILES) {
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100501 /*
502 * Effectively poll for input wherever it may be available.
503 */
504 for (;;) {
Stefan Roese80877fa2022-09-02 14:10:46 +0200505 schedule();
Patrick Delaunay4e8d61f2020-12-18 12:46:46 +0100506 if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
507 /*
508 * Upper layer may have already called tstc() so
509 * check for that first.
510 */
511 if (console_has_tstc())
512 return console_getc(file);
513 console_tstc(file);
514 } else {
515 if (console_tstc(file))
516 return console_getc(file);
517 }
518
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100519 /*
520 * If the watchdog must be rate-limited then it should
521 * already be handled in board-specific code.
522 */
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100523 if (IS_ENABLED(CONFIG_WATCHDOG))
524 udelay(1);
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100525 }
Gary Jennejohnc6dc7552008-11-06 15:04:23 +0100526 }
wdenk47d1a6e2002-11-03 00:01:44 +0000527
528 return -1;
529}
530
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100531int ftstc(int file)
wdenk47d1a6e2002-11-03 00:01:44 +0000532{
Heinrich Schuchardt1bc421b2022-10-22 11:32:34 +0200533 if ((unsigned int)file < MAX_FILES)
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100534 return console_tstc(file);
wdenk47d1a6e2002-11-03 00:01:44 +0000535
536 return -1;
537}
538
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100539void fputc(int file, const char c)
wdenk47d1a6e2002-11-03 00:01:44 +0000540{
Heinrich Schuchardt1bc421b2022-10-22 11:32:34 +0200541 if ((unsigned int)file < MAX_FILES)
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100542 console_putc(file, c);
wdenk47d1a6e2002-11-03 00:01:44 +0000543}
544
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100545void fputs(int file, const char *s)
wdenk47d1a6e2002-11-03 00:01:44 +0000546{
Heinrich Schuchardt1bc421b2022-10-22 11:32:34 +0200547 if ((unsigned int)file < MAX_FILES)
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +0100548 console_puts(file, s);
wdenk47d1a6e2002-11-03 00:01:44 +0000549}
550
Pali Rohár5aceb262022-09-05 11:31:17 +0200551#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
552void fflush(int file)
553{
Heinrich Schuchardt1bc421b2022-10-22 11:32:34 +0200554 if ((unsigned int)file < MAX_FILES)
Pali Rohár5aceb262022-09-05 11:31:17 +0200555 console_flush(file);
556}
557#endif
558
Wolfgang Denk318ef5c2010-06-20 17:14:14 +0200559int fprintf(int file, const char *fmt, ...)
wdenk47d1a6e2002-11-03 00:01:44 +0000560{
561 va_list args;
562 uint i;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200563 char printbuffer[CONFIG_SYS_PBSIZE];
wdenk47d1a6e2002-11-03 00:01:44 +0000564
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100565 va_start(args, fmt);
wdenk47d1a6e2002-11-03 00:01:44 +0000566
567 /* For this to work, printbuffer must be larger than
568 * anything we ever want to print.
569 */
Sonny Rao2813a212011-10-10 09:22:31 +0000570 i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100571 va_end(args);
wdenk47d1a6e2002-11-03 00:01:44 +0000572
573 /* Send to desired file */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100574 fputs(file, printbuffer);
Wolfgang Denk318ef5c2010-06-20 17:14:14 +0200575 return i;
wdenk47d1a6e2002-11-03 00:01:44 +0000576}
577
578/** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/
579
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200580int getchar(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000581{
Patrick Delaunayc20847f2020-12-18 12:46:45 +0100582 int ch;
583
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100584 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Mark Jackson5de56212008-08-25 19:21:30 +0100585 return 0;
Mark Jackson5de56212008-08-25 19:21:30 +0100586
Graeme Russ70600b02011-08-29 02:14:05 +0000587 if (!gd->have_console)
588 return 0;
589
Patrick Delaunayc20847f2020-12-18 12:46:45 +0100590 ch = console_record_getc();
591 if (ch != -1)
592 return ch;
Simon Glass1bb49232015-11-08 23:47:48 -0700593
wdenk47d1a6e2002-11-03 00:01:44 +0000594 if (gd->flags & GD_FLG_DEVINIT) {
595 /* Get from the standard input */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100596 return fgetc(stdin);
wdenk47d1a6e2002-11-03 00:01:44 +0000597 }
598
599 /* Send directly to the handler */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100600 return serial_getc();
wdenk47d1a6e2002-11-03 00:01:44 +0000601}
602
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100603int tstc(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000604{
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100605 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Mark Jackson5de56212008-08-25 19:21:30 +0100606 return 0;
Mark Jackson5de56212008-08-25 19:21:30 +0100607
Graeme Russ70600b02011-08-29 02:14:05 +0000608 if (!gd->have_console)
609 return 0;
Patrick Delaunayc20847f2020-12-18 12:46:45 +0100610
611 if (console_record_tstc())
612 return 1;
613
wdenk47d1a6e2002-11-03 00:01:44 +0000614 if (gd->flags & GD_FLG_DEVINIT) {
615 /* Test the standard input */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100616 return ftstc(stdin);
wdenk47d1a6e2002-11-03 00:01:44 +0000617 }
618
619 /* Send directly to the handler */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100620 return serial_tstc();
wdenk47d1a6e2002-11-03 00:01:44 +0000621}
622
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200623#define PRE_CONSOLE_FLUSHPOINT1_SERIAL 0
624#define PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL 1
625
Simon Glasse304a5e2016-10-17 20:12:36 -0600626#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
Rasmus Villemoesfb35fff2022-05-03 14:37:39 +0200627#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_VAL(PRE_CON_BUF_SZ))
Graeme Russ3c28f482011-09-01 00:48:27 +0000628
629static void pre_console_putc(const char c)
630{
Simon Glass46aaad02017-06-15 21:37:52 -0600631 char *buffer;
632
Rasmus Villemoese406a612022-05-03 15:13:27 +0200633 if (gd->precon_buf_idx < 0)
634 return;
635
Rasmus Villemoesfb35fff2022-05-03 14:37:39 +0200636 buffer = map_sysmem(CONFIG_VAL(PRE_CON_BUF_ADDR), CONFIG_VAL(PRE_CON_BUF_SZ));
Graeme Russ3c28f482011-09-01 00:48:27 +0000637
638 buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;
Simon Glass46aaad02017-06-15 21:37:52 -0600639
640 unmap_sysmem(buffer);
Graeme Russ3c28f482011-09-01 00:48:27 +0000641}
642
Soeren Moch54619bb2017-11-04 16:14:09 +0100643static void pre_console_puts(const char *s)
644{
Rasmus Villemoese406a612022-05-03 15:13:27 +0200645 if (gd->precon_buf_idx < 0)
646 return;
647
Soeren Moch54619bb2017-11-04 16:14:09 +0100648 while (*s)
649 pre_console_putc(*s++);
650}
651
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200652static void print_pre_console_buffer(int flushpoint)
Graeme Russ3c28f482011-09-01 00:48:27 +0000653{
Rasmus Villemoese406a612022-05-03 15:13:27 +0200654 long in = 0, out = 0;
Rasmus Villemoesfb35fff2022-05-03 14:37:39 +0200655 char buf_out[CONFIG_VAL(PRE_CON_BUF_SZ) + 1];
Simon Glass46aaad02017-06-15 21:37:52 -0600656 char *buf_in;
Graeme Russ3c28f482011-09-01 00:48:27 +0000657
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100658 if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200659 return;
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200660
Rasmus Villemoesfb35fff2022-05-03 14:37:39 +0200661 buf_in = map_sysmem(CONFIG_VAL(PRE_CON_BUF_ADDR), CONFIG_VAL(PRE_CON_BUF_SZ));
662 if (gd->precon_buf_idx > CONFIG_VAL(PRE_CON_BUF_SZ))
663 in = gd->precon_buf_idx - CONFIG_VAL(PRE_CON_BUF_SZ);
Graeme Russ3c28f482011-09-01 00:48:27 +0000664
Hans de Goedee355da02015-05-05 13:13:36 +0200665 while (in < gd->precon_buf_idx)
666 buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)];
Simon Glass46aaad02017-06-15 21:37:52 -0600667 unmap_sysmem(buf_in);
Hans de Goedee355da02015-05-05 13:13:36 +0200668
669 buf_out[out] = 0;
670
Rasmus Villemoese406a612022-05-03 15:13:27 +0200671 gd->precon_buf_idx = -1;
Hans de Goedee355da02015-05-05 13:13:36 +0200672 switch (flushpoint) {
673 case PRE_CONSOLE_FLUSHPOINT1_SERIAL:
674 puts(buf_out);
675 break;
676 case PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL:
Simon Glass66ee8172020-07-02 21:12:13 -0600677 console_puts_select(stdout, false, buf_out);
Hans de Goedee355da02015-05-05 13:13:36 +0200678 break;
679 }
Rasmus Villemoese406a612022-05-03 15:13:27 +0200680 gd->precon_buf_idx = in;
Graeme Russ3c28f482011-09-01 00:48:27 +0000681}
682#else
683static inline void pre_console_putc(const char c) {}
Soeren Moch54619bb2017-11-04 16:14:09 +0100684static inline void pre_console_puts(const char *s) {}
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200685static inline void print_pre_console_buffer(int flushpoint) {}
Graeme Russ3c28f482011-09-01 00:48:27 +0000686#endif
687
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100688void putc(const char c)
wdenk47d1a6e2002-11-03 00:01:44 +0000689{
Patrick Delaunay8f14b402020-11-27 11:20:56 +0100690 if (!gd)
691 return;
Patrick Delaunayc20847f2020-12-18 12:46:45 +0100692
693 console_record_putc(c);
694
Simon Glass16e3d7c2017-12-04 13:48:19 -0700695 /* sandbox can send characters to stdout before it has a console */
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100696 if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Simon Glass16e3d7c2017-12-04 13:48:19 -0700697 os_putc(c);
698 return;
699 }
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100700
Simon Glass7dd27e02015-06-23 15:38:33 -0600701 /* if we don't have a console yet, use the debug UART */
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100702 if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Simon Glass7dd27e02015-06-23 15:38:33 -0600703 printch(c);
704 return;
705 }
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100706
707 if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) {
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200708 if (!(gd->flags & GD_FLG_DEVINIT))
709 pre_console_putc(c);
wdenk927034e2004-02-08 19:38:38 +0000710 return;
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200711 }
wdenk4b6e9052004-02-06 21:48:22 +0000712
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100713 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Mark Jackson5de56212008-08-25 19:21:30 +0100714 return;
Mark Jackson5de56212008-08-25 19:21:30 +0100715
Graeme Russ70600b02011-08-29 02:14:05 +0000716 if (!gd->have_console)
Graeme Russ3c28f482011-09-01 00:48:27 +0000717 return pre_console_putc(c);
Graeme Russ70600b02011-08-29 02:14:05 +0000718
wdenk47d1a6e2002-11-03 00:01:44 +0000719 if (gd->flags & GD_FLG_DEVINIT) {
720 /* Send to the standard output */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100721 fputc(stdout, c);
wdenk47d1a6e2002-11-03 00:01:44 +0000722 } else {
723 /* Send directly to the handler */
Siarhei Siamashka616d03e2015-01-08 09:02:31 +0200724 pre_console_putc(c);
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100725 serial_putc(c);
wdenk47d1a6e2002-11-03 00:01:44 +0000726 }
727}
728
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100729void puts(const char *s)
wdenk47d1a6e2002-11-03 00:01:44 +0000730{
Patrick Delaunay8f14b402020-11-27 11:20:56 +0100731 if (!gd)
732 return;
Patrick Delaunayc20847f2020-12-18 12:46:45 +0100733
734 console_record_puts(s);
735
Simon Glassbf5c4862018-11-15 18:44:04 -0700736 /* sandbox can send characters to stdout before it has a console */
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100737 if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Simon Glassbf5c4862018-11-15 18:44:04 -0700738 os_puts(s);
739 return;
740 }
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100741
742 if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Soeren Moch54619bb2017-11-04 16:14:09 +0100743 while (*s) {
744 int ch = *s++;
745
746 printch(ch);
747 }
748 return;
749 }
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100750
751 if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) {
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200752 if (!(gd->flags & GD_FLG_DEVINIT))
753 pre_console_puts(s);
Soeren Moch54619bb2017-11-04 16:14:09 +0100754 return;
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200755 }
Soeren Moch54619bb2017-11-04 16:14:09 +0100756
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100757 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Soeren Moch54619bb2017-11-04 16:14:09 +0100758 return;
Soeren Moch54619bb2017-11-04 16:14:09 +0100759
760 if (!gd->have_console)
761 return pre_console_puts(s);
762
763 if (gd->flags & GD_FLG_DEVINIT) {
764 /* Send to the standard output */
765 fputs(stdout, s);
766 } else {
767 /* Send directly to the handler */
768 pre_console_puts(s);
769 serial_puts(s);
770 }
wdenk47d1a6e2002-11-03 00:01:44 +0000771}
Pali Rohár5aceb262022-09-05 11:31:17 +0200772
773#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
774void flush(void)
775{
776 if (!gd)
777 return;
778
779 /* sandbox can send characters to stdout before it has a console */
780 if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
781 os_flush();
782 return;
783 }
784
785 if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY))
786 return;
787
788 if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
789 return;
790
791 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
792 return;
793
794 if (!gd->have_console)
795 return;
796
797 if (gd->flags & GD_FLG_DEVINIT) {
798 /* Send to the standard output */
799 fflush(stdout);
Pali Rohára48a24f2022-09-05 11:31:19 +0200800 } else {
801 /* Send directly to the handler */
802 serial_flush();
Pali Rohár5aceb262022-09-05 11:31:17 +0200803 }
804}
805#endif
wdenk47d1a6e2002-11-03 00:01:44 +0000806
Simon Glass1bb49232015-11-08 23:47:48 -0700807#ifdef CONFIG_CONSOLE_RECORD
808int console_record_init(void)
809{
810 int ret;
811
Heinrich Schuchardt3b05a262020-02-12 18:23:49 +0100812 ret = membuff_new((struct membuff *)&gd->console_out,
Simon Glass9803ddf2021-10-23 17:26:03 -0600813 gd->flags & GD_FLG_RELOC ?
814 CONFIG_CONSOLE_RECORD_OUT_SIZE :
815 CONFIG_CONSOLE_RECORD_OUT_SIZE_F);
Simon Glass1bb49232015-11-08 23:47:48 -0700816 if (ret)
817 return ret;
Heinrich Schuchardt3b05a262020-02-12 18:23:49 +0100818 ret = membuff_new((struct membuff *)&gd->console_in,
819 CONFIG_CONSOLE_RECORD_IN_SIZE);
Simon Glass1bb49232015-11-08 23:47:48 -0700820
821 return ret;
822}
823
824void console_record_reset(void)
825{
Heinrich Schuchardt3b05a262020-02-12 18:23:49 +0100826 membuff_purge((struct membuff *)&gd->console_out);
827 membuff_purge((struct membuff *)&gd->console_in);
Simon Glassd6ed4af2021-05-08 06:59:56 -0600828 gd->flags &= ~GD_FLG_RECORD_OVF;
Simon Glass1bb49232015-11-08 23:47:48 -0700829}
830
Simon Glassdc357ef2020-07-28 19:41:11 -0600831int console_record_reset_enable(void)
Simon Glass1bb49232015-11-08 23:47:48 -0700832{
833 console_record_reset();
834 gd->flags |= GD_FLG_RECORD;
Simon Glassdc357ef2020-07-28 19:41:11 -0600835
836 return 0;
Simon Glass1bb49232015-11-08 23:47:48 -0700837}
Simon Glassb17c1582020-01-27 08:49:54 -0700838
839int console_record_readline(char *str, int maxlen)
840{
Simon Glassd6ed4af2021-05-08 06:59:56 -0600841 if (gd->flags & GD_FLG_RECORD_OVF)
842 return -ENOSPC;
843
Heinrich Schuchardt3b05a262020-02-12 18:23:49 +0100844 return membuff_readline((struct membuff *)&gd->console_out, str,
845 maxlen, ' ');
Simon Glassb17c1582020-01-27 08:49:54 -0700846}
847
848int console_record_avail(void)
849{
Heinrich Schuchardt3b05a262020-02-12 18:23:49 +0100850 return membuff_avail((struct membuff *)&gd->console_out);
Simon Glassb17c1582020-01-27 08:49:54 -0700851}
852
Steffen Jaeckele1788f92021-07-08 15:57:40 +0200853int console_in_puts(const char *str)
854{
855 return membuff_put((struct membuff *)&gd->console_in, str, strlen(str));
856}
857
Simon Glass1bb49232015-11-08 23:47:48 -0700858#endif
859
wdenk47d1a6e2002-11-03 00:01:44 +0000860/* test if ctrl-c was pressed */
861static int ctrlc_disabled = 0; /* see disable_ctrl() */
862static int ctrlc_was_pressed = 0;
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100863int ctrlc(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000864{
wdenk47d1a6e2002-11-03 00:01:44 +0000865 if (!ctrlc_disabled && gd->have_console) {
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100866 if (tstc()) {
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200867 switch (getchar()) {
wdenk47d1a6e2002-11-03 00:01:44 +0000868 case 0x03: /* ^C - Control C */
869 ctrlc_was_pressed = 1;
870 return 1;
871 default:
872 break;
873 }
874 }
875 }
Simon Glass28c5ce72014-09-14 12:40:15 -0600876
wdenk47d1a6e2002-11-03 00:01:44 +0000877 return 0;
878}
Pierre Aubert5fef9d32014-04-24 10:30:07 +0200879/* Reads user's confirmation.
880 Returns 1 if user's input is "y", "Y", "yes" or "YES"
881*/
882int confirm_yesno(void)
883{
884 int i;
885 char str_input[5];
wdenk47d1a6e2002-11-03 00:01:44 +0000886
Pierre Aubert5fef9d32014-04-24 10:30:07 +0200887 /* Flush input */
888 while (tstc())
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200889 getchar();
Pierre Aubert5fef9d32014-04-24 10:30:07 +0200890 i = 0;
891 while (i < sizeof(str_input)) {
Heinrich Schuchardtc4954fb2020-10-07 18:11:48 +0200892 str_input[i] = getchar();
Pierre Aubert5fef9d32014-04-24 10:30:07 +0200893 putc(str_input[i]);
894 if (str_input[i] == '\r')
895 break;
896 i++;
897 }
898 putc('\n');
899 if (strncmp(str_input, "y\r", 2) == 0 ||
900 strncmp(str_input, "Y\r", 2) == 0 ||
901 strncmp(str_input, "yes\r", 4) == 0 ||
902 strncmp(str_input, "YES\r", 4) == 0)
903 return 1;
904 return 0;
905}
wdenk47d1a6e2002-11-03 00:01:44 +0000906/* pass 1 to disable ctrlc() checking, 0 to enable.
907 * returns previous state
908 */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100909int disable_ctrlc(int disable)
wdenk47d1a6e2002-11-03 00:01:44 +0000910{
911 int prev = ctrlc_disabled; /* save previous state */
912
913 ctrlc_disabled = disable;
914 return prev;
915}
916
917int had_ctrlc (void)
918{
919 return ctrlc_was_pressed;
920}
921
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100922void clear_ctrlc(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000923{
924 ctrlc_was_pressed = 0;
925}
926
wdenk47d1a6e2002-11-03 00:01:44 +0000927/** U-Boot INIT FUNCTIONS *************************************************/
928
Andy Shevchenkocfaed7f2020-12-21 14:30:03 +0200929struct stdio_dev *console_search_dev(int flags, const char *name)
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200930{
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200931 struct stdio_dev *dev;
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200932
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200933 dev = stdio_get_by_name(name);
Simon Glass86f07462016-02-06 14:31:37 -0700934#ifdef CONFIG_VIDCONSOLE_AS_LCD
Patrick Delaunay60b92242020-07-01 14:56:10 +0200935 if (!dev && !strcmp(name, CONFIG_VIDCONSOLE_AS_NAME))
Simon Glass86f07462016-02-06 14:31:37 -0700936 dev = stdio_get_by_name("vidconsole");
937#endif
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200938
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100939 if (dev && (dev->flags & flags))
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200940 return dev;
941
942 return NULL;
943}
944
Mike Frysingere3d55722010-10-20 07:18:03 -0400945int console_assign(int file, const char *devname)
wdenk47d1a6e2002-11-03 00:01:44 +0000946{
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +0200947 int flag;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +0200948 struct stdio_dev *dev;
wdenk47d1a6e2002-11-03 00:01:44 +0000949
950 /* Check for valid file */
Andy Shevchenko59f324c2021-02-11 17:09:37 +0200951 flag = stdio_file_to_flags(file);
952 if (flag < 0)
953 return flag;
wdenk47d1a6e2002-11-03 00:01:44 +0000954
955 /* Check for valid device name */
956
Andy Shevchenkocfaed7f2020-12-21 14:30:03 +0200957 dev = console_search_dev(flag, devname);
wdenk47d1a6e2002-11-03 00:01:44 +0000958
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +0100959 if (dev)
960 return console_setfile(file, dev);
wdenk47d1a6e2002-11-03 00:01:44 +0000961
962 return -1;
963}
964
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200965/* return true if the 'silent' flag is removed */
966static bool console_update_silent(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000967{
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100968 unsigned long flags = gd->flags;
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200969
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100970 if (!IS_ENABLED(CONFIG_SILENT_CONSOLE))
971 return false;
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200972
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100973 if (env_get("silent")) {
974 gd->flags |= GD_FLG_SILENT;
975 return false;
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200976 }
Patrick Delaunayb39862f2019-08-02 14:58:10 +0200977
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +0100978 gd->flags &= ~GD_FLG_SILENT;
979
980 return !!(flags & GD_FLG_SILENT);
Simon Glassc9c5c9f2017-06-15 21:37:50 -0600981}
982
983int console_announce_r(void)
984{
985#if !CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
986 char buf[DISPLAY_OPTIONS_BANNER_LENGTH];
987
988 display_options_get_banner(false, buf, sizeof(buf));
989
Simon Glass66ee8172020-07-02 21:12:13 -0600990 console_puts_select(stdout, false, buf);
Simon Glassc9c5c9f2017-06-15 21:37:50 -0600991#endif
992
993 return 0;
Chris Packhamfab806d2016-09-23 15:59:43 +1200994}
995
996/* Called before relocation - use serial functions */
997int console_init_f(void)
998{
999 gd->have_console = 1;
1000
1001 console_update_silent();
wdenk808532a2003-10-10 10:05:42 +00001002
Siarhei Siamashka616d03e2015-01-08 09:02:31 +02001003 print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);
Graeme Russ3c28f482011-09-01 00:48:27 +00001004
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +01001005 return 0;
wdenk47d1a6e2002-11-03 00:01:44 +00001006}
1007
Jean-Christophe PLAGNIOL-VILLARD5a309362009-05-16 12:14:55 +02001008void stdio_print_current_devices(void)
1009{
Jean-Christophe PLAGNIOL-VILLARD5a309362009-05-16 12:14:55 +02001010 /* Print information */
1011 puts("In: ");
1012 if (stdio_devices[stdin] == NULL) {
1013 puts("No input devices available!\n");
1014 } else {
1015 printf ("%s\n", stdio_devices[stdin]->name);
1016 }
1017
1018 puts("Out: ");
1019 if (stdio_devices[stdout] == NULL) {
1020 puts("No output devices available!\n");
1021 } else {
1022 printf ("%s\n", stdio_devices[stdout]->name);
1023 }
1024
1025 puts("Err: ");
1026 if (stdio_devices[stderr] == NULL) {
1027 puts("No error devices available!\n");
1028 } else {
1029 printf ("%s\n", stdio_devices[stderr]->name);
1030 }
Jean-Christophe PLAGNIOL-VILLARD5a309362009-05-16 12:14:55 +02001031}
1032
Simon Glassdfc25352017-01-16 07:03:26 -07001033#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
wdenk47d1a6e2002-11-03 00:01:44 +00001034/* Called after the relocation - use desired console functions */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +01001035int console_init_r(void)
wdenk47d1a6e2002-11-03 00:01:44 +00001036{
1037 char *stdinname, *stdoutname, *stderrname;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +02001038 struct stdio_dev *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
wdenk05939202004-04-18 17:39:38 +00001039 int i;
Gary Jennejohnc6dc7552008-11-06 15:04:23 +01001040 int iomux_err = 0;
Patrick Delaunayb39862f2019-08-02 14:58:10 +02001041 int flushpoint;
wdenk47d1a6e2002-11-03 00:01:44 +00001042
Patrick Delaunay46b610d2019-08-02 14:58:09 +02001043 /* update silent for env loaded from flash (initr_env) */
Patrick Delaunayb39862f2019-08-02 14:58:10 +02001044 if (console_update_silent())
1045 flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL;
1046 else
1047 flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL;
Patrick Delaunay46b610d2019-08-02 14:58:09 +02001048
wdenk47d1a6e2002-11-03 00:01:44 +00001049 /* set default handlers at first */
Martin Dorwigcb2c2862015-01-26 15:22:54 -07001050 gd->jt->getc = serial_getc;
1051 gd->jt->tstc = serial_tstc;
1052 gd->jt->putc = serial_putc;
1053 gd->jt->puts = serial_puts;
1054 gd->jt->printf = serial_printf;
wdenk47d1a6e2002-11-03 00:01:44 +00001055
1056 /* stdin stdout and stderr are in environment */
1057 /* scan for it */
Simon Glass64b723f2017-08-03 12:22:12 -06001058 stdinname = env_get("stdin");
1059 stdoutname = env_get("stdout");
1060 stderrname = env_get("stderr");
wdenk47d1a6e2002-11-03 00:01:44 +00001061
Wolfgang Denka1be4762008-05-20 16:00:29 +02001062 if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */
Andy Shevchenkocfaed7f2020-12-21 14:30:03 +02001063 inputdev = console_search_dev(DEV_FLAGS_INPUT, stdinname);
1064 outputdev = console_search_dev(DEV_FLAGS_OUTPUT, stdoutname);
1065 errdev = console_search_dev(DEV_FLAGS_OUTPUT, stderrname);
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +01001066 if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
1067 iomux_err = iomux_doenv(stdin, stdinname);
1068 iomux_err += iomux_doenv(stdout, stdoutname);
1069 iomux_err += iomux_doenv(stderr, stderrname);
1070 if (!iomux_err)
1071 /* Successful, so skip all the code below. */
1072 goto done;
1073 }
wdenk47d1a6e2002-11-03 00:01:44 +00001074 }
1075 /* if the devices are overwritten or not found, use default device */
1076 if (inputdev == NULL) {
Andy Shevchenkocfaed7f2020-12-21 14:30:03 +02001077 inputdev = console_search_dev(DEV_FLAGS_INPUT, "serial");
wdenk47d1a6e2002-11-03 00:01:44 +00001078 }
1079 if (outputdev == NULL) {
Andy Shevchenkocfaed7f2020-12-21 14:30:03 +02001080 outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
wdenk47d1a6e2002-11-03 00:01:44 +00001081 }
1082 if (errdev == NULL) {
Andy Shevchenkocfaed7f2020-12-21 14:30:03 +02001083 errdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
wdenk47d1a6e2002-11-03 00:01:44 +00001084 }
1085 /* Initializes output console first */
1086 if (outputdev != NULL) {
Gary Jennejohnc6dc7552008-11-06 15:04:23 +01001087 /* need to set a console if not done above. */
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +01001088 console_doenv(stdout, outputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001089 }
1090 if (errdev != NULL) {
Gary Jennejohnc6dc7552008-11-06 15:04:23 +01001091 /* need to set a console if not done above. */
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +01001092 console_doenv(stderr, errdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001093 }
1094 if (inputdev != NULL) {
Gary Jennejohnc6dc7552008-11-06 15:04:23 +01001095 /* need to set a console if not done above. */
Jean-Christophe PLAGNIOL-VILLARD63331a02009-02-01 17:07:52 +01001096 console_doenv(stdin, inputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001097 }
1098
Gary Jennejohnc6dc7552008-11-06 15:04:23 +01001099done:
Gary Jennejohnc6dc7552008-11-06 15:04:23 +01001100
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +01001101 if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
1102 stdio_print_current_devices();
1103
Simon Glass86f07462016-02-06 14:31:37 -07001104#ifdef CONFIG_VIDCONSOLE_AS_LCD
Patrick Delaunay60b92242020-07-01 14:56:10 +02001105 if (strstr(stdoutname, CONFIG_VIDCONSOLE_AS_NAME))
Anatolij Gustschin47020642020-05-23 17:11:20 +02001106 printf("Warning: Please change '%s' to 'vidconsole' in stdout/stderr environment vars\n",
Patrick Delaunay60b92242020-07-01 14:56:10 +02001107 CONFIG_VIDCONSOLE_AS_NAME);
Simon Glass86f07462016-02-06 14:31:37 -07001108#endif
wdenk47d1a6e2002-11-03 00:01:44 +00001109
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +01001110 if (IS_ENABLED(CONFIG_SYS_CONSOLE_ENV_OVERWRITE)) {
1111 /* set the environment variables (will overwrite previous env settings) */
1112 for (i = 0; i < MAX_FILES; i++)
1113 env_set(stdio_names[i], stdio_devices[i]->name);
wdenk47d1a6e2002-11-03 00:01:44 +00001114 }
wdenk47d1a6e2002-11-03 00:01:44 +00001115
Joe Hershbergera46f7702012-12-11 22:16:19 -06001116 gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
1117
Patrick Delaunayb39862f2019-08-02 14:58:10 +02001118 print_pre_console_buffer(flushpoint);
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +01001119 return 0;
wdenk47d1a6e2002-11-03 00:01:44 +00001120}
1121
Simon Glassdfc25352017-01-16 07:03:26 -07001122#else /* !CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */
wdenk47d1a6e2002-11-03 00:01:44 +00001123
1124/* Called after the relocation - use desired console functions */
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +01001125int console_init_r(void)
wdenk47d1a6e2002-11-03 00:01:44 +00001126{
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +02001127 struct stdio_dev *inputdev = NULL, *outputdev = NULL;
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +02001128 int i;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +02001129 struct list_head *list = stdio_get_list();
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +02001130 struct list_head *pos;
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +02001131 struct stdio_dev *dev;
Patrick Delaunayb39862f2019-08-02 14:58:10 +02001132 int flushpoint;
wdenk47d1a6e2002-11-03 00:01:44 +00001133
Patrick Delaunay46b610d2019-08-02 14:58:09 +02001134 /* update silent for env loaded from flash (initr_env) */
Patrick Delaunayb39862f2019-08-02 14:58:10 +02001135 if (console_update_silent())
1136 flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL;
1137 else
1138 flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL;
Chris Packhamfab806d2016-09-23 15:59:43 +12001139
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +01001140 /*
1141 * suppress all output if splash screen is enabled and we have
Anatolij Gustschinec8744a2010-03-16 15:29:33 +01001142 * a bmp to display. We redirect the output from frame buffer
1143 * console to serial console in this case or suppress it if
1144 * "silent" mode was requested.
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +01001145 */
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +01001146 if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) {
Anatolij Gustschinec8744a2010-03-16 15:29:33 +01001147 if (!(gd->flags & GD_FLG_SILENT))
Andy Shevchenkocfaed7f2020-12-21 14:30:03 +02001148 outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial");
Anatolij Gustschinec8744a2010-03-16 15:29:33 +01001149 }
wdenk808532a2003-10-10 10:05:42 +00001150
wdenk47d1a6e2002-11-03 00:01:44 +00001151 /* Scan devices looking for input and output devices */
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +02001152 list_for_each(pos, list) {
Jean-Christophe PLAGNIOL-VILLARD2a7a0312009-05-16 12:14:54 +02001153 dev = list_entry(pos, struct stdio_dev, list);
wdenk47d1a6e2002-11-03 00:01:44 +00001154
1155 if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
1156 inputdev = dev;
1157 }
1158 if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
1159 outputdev = dev;
1160 }
Jean-Christophe PLAGNIOL-VILLARD8a4a7842008-08-31 04:24:55 +02001161 if(inputdev && outputdev)
1162 break;
wdenk47d1a6e2002-11-03 00:01:44 +00001163 }
1164
1165 /* Initializes output console first */
1166 if (outputdev != NULL) {
Andy Shevchenkoba69b2c2021-02-11 17:09:39 +02001167 console_setfile_and_devices(stdout, outputdev);
1168 console_setfile_and_devices(stderr, outputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001169 }
1170
1171 /* Initializes input console */
Andy Shevchenkoba69b2c2021-02-11 17:09:39 +02001172 if (inputdev != NULL)
1173 console_setfile_and_devices(stdin, inputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001174
Patrick Delaunay4b0b56f2020-12-18 12:46:43 +01001175 if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
1176 stdio_print_current_devices();
wdenk47d1a6e2002-11-03 00:01:44 +00001177
1178 /* Setting environment variables */
Tom Rini66c4d712018-05-03 09:12:26 -04001179 for (i = 0; i < MAX_FILES; i++) {
Simon Glass6a38e412017-08-03 12:22:09 -06001180 env_set(stdio_names[i], stdio_devices[i]->name);
wdenk47d1a6e2002-11-03 00:01:44 +00001181 }
1182
Joe Hershbergera46f7702012-12-11 22:16:19 -06001183 gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
1184
Patrick Delaunayb39862f2019-08-02 14:58:10 +02001185 print_pre_console_buffer(flushpoint);
Jean-Christophe PLAGNIOL-VILLARDc7dc6722009-02-01 17:07:51 +01001186 return 0;
wdenk47d1a6e2002-11-03 00:01:44 +00001187}
1188
Simon Glassdfc25352017-01-16 07:03:26 -07001189#endif /* CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */