blob: ce0c9b69f58cb7b1f2b086950adb97e1f0d31fff [file] [log] [blame]
Tom Rini83d290c2018-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 Glass24b852a2015-11-08 23:47:45 -07008#include <console.h>
Simon Glassd6ea5302015-06-23 15:38:33 -06009#include <debug_uart.h>
Simon Glass4e4bf942022-07-31 12:28:48 -060010#include <display_options.h>
Simon Glass7b3c4c32017-07-27 09:31:04 -060011#include <dm.h>
Simon Glass9fb625c2019-08-01 09:46:51 -060012#include <env.h>
wdenk47d1a6e2002-11-03 00:01:44 +000013#include <stdarg.h>
Jeroen Hofstee482f4692014-10-08 22:57:48 +020014#include <iomux.h>
wdenk47d1a6e2002-11-03 00:01:44 +000015#include <malloc.h>
Simon Glass4e6bafa2017-06-15 21:37:52 -060016#include <mapmem.h>
Simon Glass91b136c2013-11-10 10:27:01 -070017#include <os.h>
Joe Hershberger849d5d92012-12-11 22:16:29 -060018#include <serial.h>
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +020019#include <stdio_dev.h>
wdenk27b207f2003-07-24 23:38:38 +000020#include <exports.h>
Simon Glassf3998fd2019-08-02 09:44:25 -060021#include <env_internal.h>
Andreas J. Reichel64407462016-07-13 12:56:51 +020022#include <watchdog.h>
Simon Glass401d1c42020-10-30 21:38:53 -060023#include <asm/global_data.h>
Simon Glassc05ed002020-05-10 11:40:11 -060024#include <linux/delay.h>
wdenk47d1a6e2002-11-03 00:01:44 +000025
Wolfgang Denkd87080b2006-03-31 18:32:53 +020026DECLARE_GLOBAL_DATA_PTR;
27
Joe Hershberger849d5d92012-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 Delaunayc04f8562020-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 Hershberger849d5d92012-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 Hershbergere080d542012-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 Delaunayc04f8562020-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 Hershbergere080d542012-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 Delaunay1e993712020-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 Glassc1a2bb42021-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 Delaunay1e993712020-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 Glassc1a2bb42021-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 Delaunay1e993712020-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 Glassb0265422017-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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200163#ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100164extern int overwrite_console(void);
165#define OVERWRITE_CONSOLE overwrite_console()
wdenk47d1a6e2002-11-03 00:01:44 +0000166#else
wdenk83e40ba2005-03-31 18:42:15 +0000167#define OVERWRITE_CONSOLE 0
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200168#endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */
wdenk47d1a6e2002-11-03 00:01:44 +0000169
Simon Glassb0265422017-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-VILLARD52cb4d42009-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 Shevchenko41f668b2020-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 Schuchardtc670aee2020-10-07 18:11:48 +0200196 gd->jt->getc = getchar;
Martin Dorwig49cad542015-01-26 15:22:54 -0700197 gd->jt->tstc = tstc;
wdenk47d1a6e2002-11-03 00:01:44 +0000198 break;
199 case stdout:
Martin Dorwig49cad542015-01-26 15:22:54 -0700200 gd->jt->putc = putc;
201 gd->jt->puts = puts;
Pali Rohár974f4832022-09-05 11:31:17 +0200202 STDIO_DEV_ASSIGN_FLUSH(gd->jt, flush);
Martin Dorwig49cad542015-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 Glass42f9f912017-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 Schuchardt185f8122022-01-19 18:05:50 +0100218 * Return: true if this device is in the serial uclass (or for pre-driver-model,
Simon Glass7b3c4c32017-07-27 09:31:04 -0600219 * whether it is called "serial".
Simon Glass42f9f912017-07-27 09:31:03 -0600220 */
221static bool console_dev_is_serial(struct stdio_dev *sdev)
222{
223 bool is_serial;
224
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100225 if (IS_ENABLED(CONFIG_DM_SERIAL) && (sdev->flags & DEV_FLAGS_DM)) {
Simon Glass7b3c4c32017-07-27 09:31:04 -0600226 struct udevice *dev = sdev->priv;
227
228 is_serial = device_get_uclass_id(dev) == UCLASS_SERIAL;
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100229 } else {
230 is_serial = !strcmp(sdev->name, "serial");
231 }
Simon Glass42f9f912017-07-27 09:31:03 -0600232
233 return is_serial;
234}
235
Simon Glassb0265422017-01-16 07:03:26 -0700236#if CONFIG_IS_ENABLED(CONSOLE_MUX)
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100237/** Console I/O multiplexing *******************************************/
238
Patrick Delaunaya17b38c2020-12-18 12:46:46 +0100239/* tstcdev: save the last stdio device with pending characters, with tstc != 0 */
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200240static struct stdio_dev *tstcdev;
241struct stdio_dev **console_devices[MAX_FILES];
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100242int cd_count[MAX_FILES];
243
Andy Shevchenko09d8f072021-02-11 17:09:39 +0200244static void console_devices_set(int file, struct stdio_dev *dev)
Patrick Delaunay45375ad2020-12-18 12:46:44 +0100245{
246 console_devices[file][0] = dev;
Andy Shevchenko20a7d352021-02-11 17:09:38 +0200247 cd_count[file] = 1;
Patrick Delaunay45375ad2020-12-18 12:46:44 +0100248}
249
Andy Shevchenko95aaf402020-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 Shevchenkob672c162021-02-11 17:09:41 +0200263 int i;
Andy Shevchenko95aaf402020-12-21 14:30:01 +0200264
265 for (i = 0; i < ARRAY_SIZE(cd_count); i++) {
266 if (i == file)
267 continue;
268
Andy Shevchenkob672c162021-02-11 17:09:41 +0200269 if (iomux_match_device(console_devices[i], cd_count[i], sdev) >= 0)
270 return false;
Andy Shevchenko95aaf402020-12-21 14:30:01 +0200271 }
272 return true;
273}
274
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100275/*
Heinrich Schuchardtc670aee2020-10-07 18:11:48 +0200276 * This depends on tstc() always being called before getchar().
Gary Jennejohn16a28ef2008-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-VILLARD5f032012009-02-01 17:07:52 +0100281static int console_getc(int file)
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100282{
283 unsigned char ret;
284
285 /* This is never called with testcdev == NULL */
Simon Glass709ea542014-07-23 06:54:59 -0600286 ret = tstcdev->getc(tstcdev);
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100287 tstcdev = NULL;
288 return ret;
289}
290
Patrick Delaunaya17b38c2020-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-VILLARD5f032012009-02-01 17:07:52 +0100297static int console_tstc(int file)
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100298{
299 int i, ret;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200300 struct stdio_dev *dev;
Joe Hershbergerb2f58d82018-07-02 20:06:48 -0500301 int prev;
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100302
Joe Hershbergerb2f58d82018-07-02 20:06:48 -0500303 prev = disable_ctrlc(1);
Andy Shevchenko400797c2021-02-11 17:09:42 +0200304 for_each_console_dev(i, file, dev) {
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100305 if (dev->tstc != NULL) {
Simon Glass709ea542014-07-23 06:54:59 -0600306 ret = dev->tstc(dev);
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100307 if (ret > 0) {
308 tstcdev = dev;
Joe Hershbergerb2f58d82018-07-02 20:06:48 -0500309 disable_ctrlc(prev);
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100310 return ret;
311 }
312 }
313 }
Joe Hershbergerb2f58d82018-07-02 20:06:48 -0500314 disable_ctrlc(prev);
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100315
316 return 0;
317}
318
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100319static void console_putc(int file, const char c)
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100320{
321 int i;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200322 struct stdio_dev *dev;
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100323
Andy Shevchenko400797c2021-02-11 17:09:42 +0200324 for_each_console_dev(i, file, dev) {
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100325 if (dev->putc != NULL)
Simon Glass709ea542014-07-23 06:54:59 -0600326 dev->putc(dev, c);
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100327 }
328}
329
Simon Glass493a4c82020-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 Siamashka27669662015-01-08 09:02:31 +0200339{
340 int i;
341 struct stdio_dev *dev;
342
Andy Shevchenko400797c2021-02-11 17:09:42 +0200343 for_each_console_dev(i, file, dev) {
344 bool is_serial = console_dev_is_serial(dev);
Simon Glass493a4c82020-07-02 21:12:13 -0600345
Simon Glass493a4c82020-07-02 21:12:13 -0600346 if (dev->puts && serial_only == is_serial)
Hans de Goedea8552c72015-05-05 13:13:36 +0200347 dev->puts(dev, s);
Siarhei Siamashka27669662015-01-08 09:02:31 +0200348 }
349}
Siarhei Siamashka27669662015-01-08 09:02:31 +0200350
Simon Glass493a4c82020-07-02 21:12:13 -0600351void console_puts_select_stderr(bool serial_only, const char *s)
352{
Simon Glass4057e272021-11-19 13:23:47 -0700353 if (gd->flags & GD_FLG_DEVINIT)
354 console_puts_select(stderr, serial_only, s);
Simon Glass493a4c82020-07-02 21:12:13 -0600355}
356
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100357static void console_puts(int file, const char *s)
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100358{
359 int i;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200360 struct stdio_dev *dev;
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100361
Andy Shevchenko400797c2021-02-11 17:09:42 +0200362 for_each_console_dev(i, file, dev) {
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100363 if (dev->puts != NULL)
Simon Glass709ea542014-07-23 06:54:59 -0600364 dev->puts(dev, s);
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100365 }
366}
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100367
Pali Rohár974f4832022-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 Rini5e63c962019-10-30 09:18:43 -0400381#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200382static inline void console_doenv(int file, struct stdio_dev *dev)
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100383{
384 iomux_doenv(file, dev->name);
385}
Tom Rini5e63c962019-10-30 09:18:43 -0400386#endif
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100387#else
Patrick Delaunay45375ad2020-12-18 12:46:44 +0100388
Andy Shevchenko09d8f072021-02-11 17:09:39 +0200389static void console_devices_set(int file, struct stdio_dev *dev)
Patrick Delaunay45375ad2020-12-18 12:46:44 +0100390{
391}
392
Andy Shevchenko95aaf402020-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-VILLARD5f032012009-02-01 17:07:52 +0100398static inline int console_getc(int file)
399{
Simon Glass709ea542014-07-23 06:54:59 -0600400 return stdio_devices[file]->getc(stdio_devices[file]);
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100401}
402
Patrick Delaunaya17b38c2020-12-18 12:46:46 +0100403static bool console_has_tstc(void)
404{
405 return false;
406}
407
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100408static inline int console_tstc(int file)
409{
Simon Glass709ea542014-07-23 06:54:59 -0600410 return stdio_devices[file]->tstc(stdio_devices[file]);
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100411}
412
413static inline void console_putc(int file, const char c)
414{
Simon Glass709ea542014-07-23 06:54:59 -0600415 stdio_devices[file]->putc(stdio_devices[file], c);
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100416}
417
Simon Glass493a4c82020-07-02 21:12:13 -0600418void console_puts_select(int file, bool serial_only, const char *s)
Siarhei Siamashka27669662015-01-08 09:02:31 +0200419{
Simon Glass4057e272021-11-19 13:23:47 -0700420 if ((gd->flags & GD_FLG_DEVINIT) &&
421 serial_only == console_dev_is_serial(stdio_devices[file]))
Hans de Goedea8552c72015-05-05 13:13:36 +0200422 stdio_devices[file]->puts(stdio_devices[file], s);
Siarhei Siamashka27669662015-01-08 09:02:31 +0200423}
Siarhei Siamashka27669662015-01-08 09:02:31 +0200424
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100425static inline void console_puts(int file, const char *s)
426{
Simon Glass709ea542014-07-23 06:54:59 -0600427 stdio_devices[file]->puts(stdio_devices[file], s);
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100428}
429
Pali Rohár974f4832022-09-05 11:31:17 +0200430#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
437
Tom Rini5e63c962019-10-30 09:18:43 -0400438#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200439static inline void console_doenv(int file, struct stdio_dev *dev)
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100440{
441 console_setfile(file, dev);
442}
Tom Rini5e63c962019-10-30 09:18:43 -0400443#endif
Simon Glassb0265422017-01-16 07:03:26 -0700444#endif /* CONIFIG_IS_ENABLED(CONSOLE_MUX) */
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100445
Andy Shevchenko09d8f072021-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 Shevchenko41f668b2020-12-21 14:30:00 +0200452int console_start(int file, struct stdio_dev *sdev)
453{
454 int error;
455
Andy Shevchenko95aaf402020-12-21 14:30:01 +0200456 if (!console_needs_start_stop(file, sdev))
457 return 0;
458
Andy Shevchenko41f668b2020-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 Shevchenko95aaf402020-12-21 14:30:01 +0200471 if (!console_needs_start_stop(file, sdev))
472 return;
473
Andy Shevchenko41f668b2020-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 Denkd9c27252010-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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200484 char printbuffer[CONFIG_SYS_PBSIZE];
wdenk47d1a6e2002-11-03 00:01:44 +0000485
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-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 Rao068af6f2011-10-10 09:22:31 +0000491 i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100492 va_end(args);
wdenk47d1a6e2002-11-03 00:01:44 +0000493
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100494 serial_puts(printbuffer);
Wolfgang Denkd9c27252010-06-20 17:14:14 +0200495 return i;
wdenk47d1a6e2002-11-03 00:01:44 +0000496}
497
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100498int fgetc(int file)
wdenk47d1a6e2002-11-03 00:01:44 +0000499{
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100500 if (file < MAX_FILES) {
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100501 /*
502 * Effectively poll for input wherever it may be available.
503 */
504 for (;;) {
Stefan Roese29caf932022-09-02 14:10:46 +0200505 schedule();
Patrick Delaunaya17b38c2020-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 Jennejohn16a28ef2008-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 Delaunayc04f8562020-12-18 12:46:43 +0100523 if (IS_ENABLED(CONFIG_WATCHDOG))
524 udelay(1);
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100525 }
Gary Jennejohn16a28ef2008-11-06 15:04:23 +0100526 }
wdenk47d1a6e2002-11-03 00:01:44 +0000527
528 return -1;
529}
530
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100531int ftstc(int file)
wdenk47d1a6e2002-11-03 00:01:44 +0000532{
533 if (file < MAX_FILES)
Jean-Christophe PLAGNIOL-VILLARD5f032012009-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-VILLARDec6f1492009-02-01 17:07:51 +0100539void fputc(int file, const char c)
wdenk47d1a6e2002-11-03 00:01:44 +0000540{
541 if (file < MAX_FILES)
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100542 console_putc(file, c);
wdenk47d1a6e2002-11-03 00:01:44 +0000543}
544
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100545void fputs(int file, const char *s)
wdenk47d1a6e2002-11-03 00:01:44 +0000546{
547 if (file < MAX_FILES)
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +0100548 console_puts(file, s);
wdenk47d1a6e2002-11-03 00:01:44 +0000549}
550
Pali Rohár974f4832022-09-05 11:31:17 +0200551#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
552void fflush(int file)
553{
554 if (file < MAX_FILES)
555 console_flush(file);
556}
557#endif
558
Wolfgang Denkd9c27252010-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-VILLARD6d0f6bc2008-10-16 15:01:15 +0200563 char printbuffer[CONFIG_SYS_PBSIZE];
wdenk47d1a6e2002-11-03 00:01:44 +0000564
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-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 Rao068af6f2011-10-10 09:22:31 +0000570 i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100571 va_end(args);
wdenk47d1a6e2002-11-03 00:01:44 +0000572
573 /* Send to desired file */
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100574 fputs(file, printbuffer);
Wolfgang Denkd9c27252010-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 Schuchardtc670aee2020-10-07 18:11:48 +0200580int getchar(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000581{
Patrick Delaunay1e993712020-12-18 12:46:45 +0100582 int ch;
583
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100584 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Mark Jacksonf5c3ba72008-08-25 19:21:30 +0100585 return 0;
Mark Jacksonf5c3ba72008-08-25 19:21:30 +0100586
Graeme Russe3e454c2011-08-29 02:14:05 +0000587 if (!gd->have_console)
588 return 0;
589
Patrick Delaunay1e993712020-12-18 12:46:45 +0100590 ch = console_record_getc();
591 if (ch != -1)
592 return ch;
Simon Glass9854a872015-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-VILLARDec6f1492009-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-VILLARDec6f1492009-02-01 17:07:51 +0100600 return serial_getc();
wdenk47d1a6e2002-11-03 00:01:44 +0000601}
602
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100603int tstc(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000604{
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100605 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Mark Jacksonf5c3ba72008-08-25 19:21:30 +0100606 return 0;
Mark Jacksonf5c3ba72008-08-25 19:21:30 +0100607
Graeme Russe3e454c2011-08-29 02:14:05 +0000608 if (!gd->have_console)
609 return 0;
Patrick Delaunay1e993712020-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-VILLARDec6f1492009-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-VILLARDec6f1492009-02-01 17:07:51 +0100620 return serial_tstc();
wdenk47d1a6e2002-11-03 00:01:44 +0000621}
622
Siarhei Siamashka27669662015-01-08 09:02:31 +0200623#define PRE_CONSOLE_FLUSHPOINT1_SERIAL 0
624#define PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL 1
625
Simon Glass8f925582016-10-17 20:12:36 -0600626#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
Rasmus Villemoescff29632022-05-03 14:37:39 +0200627#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_VAL(PRE_CON_BUF_SZ))
Graeme Russ9558b482011-09-01 00:48:27 +0000628
629static void pre_console_putc(const char c)
630{
Simon Glass4e6bafa2017-06-15 21:37:52 -0600631 char *buffer;
632
Rasmus Villemoes04a20ca2022-05-03 15:13:27 +0200633 if (gd->precon_buf_idx < 0)
634 return;
635
Rasmus Villemoescff29632022-05-03 14:37:39 +0200636 buffer = map_sysmem(CONFIG_VAL(PRE_CON_BUF_ADDR), CONFIG_VAL(PRE_CON_BUF_SZ));
Graeme Russ9558b482011-09-01 00:48:27 +0000637
638 buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;
Simon Glass4e6bafa2017-06-15 21:37:52 -0600639
640 unmap_sysmem(buffer);
Graeme Russ9558b482011-09-01 00:48:27 +0000641}
642
Soeren Mochbe135cc2017-11-04 16:14:09 +0100643static void pre_console_puts(const char *s)
644{
Rasmus Villemoes04a20ca2022-05-03 15:13:27 +0200645 if (gd->precon_buf_idx < 0)
646 return;
647
Soeren Mochbe135cc2017-11-04 16:14:09 +0100648 while (*s)
649 pre_console_putc(*s++);
650}
651
Siarhei Siamashka27669662015-01-08 09:02:31 +0200652static void print_pre_console_buffer(int flushpoint)
Graeme Russ9558b482011-09-01 00:48:27 +0000653{
Rasmus Villemoes04a20ca2022-05-03 15:13:27 +0200654 long in = 0, out = 0;
Rasmus Villemoescff29632022-05-03 14:37:39 +0200655 char buf_out[CONFIG_VAL(PRE_CON_BUF_SZ) + 1];
Simon Glass4e6bafa2017-06-15 21:37:52 -0600656 char *buf_in;
Graeme Russ9558b482011-09-01 00:48:27 +0000657
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100658 if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
Patrick Delaunay13551b92019-08-02 14:58:10 +0200659 return;
Patrick Delaunay13551b92019-08-02 14:58:10 +0200660
Rasmus Villemoescff29632022-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 Russ9558b482011-09-01 00:48:27 +0000664
Hans de Goedea8552c72015-05-05 13:13:36 +0200665 while (in < gd->precon_buf_idx)
666 buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)];
Simon Glass4e6bafa2017-06-15 21:37:52 -0600667 unmap_sysmem(buf_in);
Hans de Goedea8552c72015-05-05 13:13:36 +0200668
669 buf_out[out] = 0;
670
Rasmus Villemoes04a20ca2022-05-03 15:13:27 +0200671 gd->precon_buf_idx = -1;
Hans de Goedea8552c72015-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 Glass493a4c82020-07-02 21:12:13 -0600677 console_puts_select(stdout, false, buf_out);
Hans de Goedea8552c72015-05-05 13:13:36 +0200678 break;
679 }
Rasmus Villemoes04a20ca2022-05-03 15:13:27 +0200680 gd->precon_buf_idx = in;
Graeme Russ9558b482011-09-01 00:48:27 +0000681}
682#else
683static inline void pre_console_putc(const char c) {}
Soeren Mochbe135cc2017-11-04 16:14:09 +0100684static inline void pre_console_puts(const char *s) {}
Siarhei Siamashka27669662015-01-08 09:02:31 +0200685static inline void print_pre_console_buffer(int flushpoint) {}
Graeme Russ9558b482011-09-01 00:48:27 +0000686#endif
687
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100688void putc(const char c)
wdenk47d1a6e2002-11-03 00:01:44 +0000689{
Patrick Delaunay93cdb522020-11-27 11:20:56 +0100690 if (!gd)
691 return;
Patrick Delaunay1e993712020-12-18 12:46:45 +0100692
693 console_record_putc(c);
694
Simon Glass64e9b4f2017-12-04 13:48:19 -0700695 /* sandbox can send characters to stdout before it has a console */
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100696 if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Simon Glass64e9b4f2017-12-04 13:48:19 -0700697 os_putc(c);
698 return;
699 }
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100700
Simon Glassd6ea5302015-06-23 15:38:33 -0600701 /* if we don't have a console yet, use the debug UART */
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100702 if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Simon Glassd6ea5302015-06-23 15:38:33 -0600703 printch(c);
704 return;
705 }
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100706
707 if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) {
Patrick Delaunay13551b92019-08-02 14:58:10 +0200708 if (!(gd->flags & GD_FLG_DEVINIT))
709 pre_console_putc(c);
wdenkf6e20fc2004-02-08 19:38:38 +0000710 return;
Patrick Delaunay13551b92019-08-02 14:58:10 +0200711 }
wdenka6cccae2004-02-06 21:48:22 +0000712
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100713 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Mark Jacksonf5c3ba72008-08-25 19:21:30 +0100714 return;
Mark Jacksonf5c3ba72008-08-25 19:21:30 +0100715
Graeme Russe3e454c2011-08-29 02:14:05 +0000716 if (!gd->have_console)
Graeme Russ9558b482011-09-01 00:48:27 +0000717 return pre_console_putc(c);
Graeme Russe3e454c2011-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-VILLARDec6f1492009-02-01 17:07:51 +0100721 fputc(stdout, c);
wdenk47d1a6e2002-11-03 00:01:44 +0000722 } else {
723 /* Send directly to the handler */
Siarhei Siamashka27669662015-01-08 09:02:31 +0200724 pre_console_putc(c);
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100725 serial_putc(c);
wdenk47d1a6e2002-11-03 00:01:44 +0000726 }
727}
728
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100729void puts(const char *s)
wdenk47d1a6e2002-11-03 00:01:44 +0000730{
Patrick Delaunay93cdb522020-11-27 11:20:56 +0100731 if (!gd)
732 return;
Patrick Delaunay1e993712020-12-18 12:46:45 +0100733
734 console_record_puts(s);
735
Simon Glass36bcea62018-11-15 18:44:04 -0700736 /* sandbox can send characters to stdout before it has a console */
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100737 if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Simon Glass36bcea62018-11-15 18:44:04 -0700738 os_puts(s);
739 return;
740 }
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100741
742 if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) {
Soeren Mochbe135cc2017-11-04 16:14:09 +0100743 while (*s) {
744 int ch = *s++;
745
746 printch(ch);
747 }
748 return;
749 }
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100750
751 if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) {
Patrick Delaunay13551b92019-08-02 14:58:10 +0200752 if (!(gd->flags & GD_FLG_DEVINIT))
753 pre_console_puts(s);
Soeren Mochbe135cc2017-11-04 16:14:09 +0100754 return;
Patrick Delaunay13551b92019-08-02 14:58:10 +0200755 }
Soeren Mochbe135cc2017-11-04 16:14:09 +0100756
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100757 if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
Soeren Mochbe135cc2017-11-04 16:14:09 +0100758 return;
Soeren Mochbe135cc2017-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}
772
Pali Rohár974f4832022-09-05 11:31:17 +0200773#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);
800 }
801}
802#endif
803
Simon Glass9854a872015-11-08 23:47:48 -0700804#ifdef CONFIG_CONSOLE_RECORD
805int console_record_init(void)
806{
807 int ret;
808
Heinrich Schuchardta3a9e042020-02-12 18:23:49 +0100809 ret = membuff_new((struct membuff *)&gd->console_out,
Simon Glass8ce465e2021-10-23 17:26:03 -0600810 gd->flags & GD_FLG_RELOC ?
811 CONFIG_CONSOLE_RECORD_OUT_SIZE :
812 CONFIG_CONSOLE_RECORD_OUT_SIZE_F);
Simon Glass9854a872015-11-08 23:47:48 -0700813 if (ret)
814 return ret;
Heinrich Schuchardta3a9e042020-02-12 18:23:49 +0100815 ret = membuff_new((struct membuff *)&gd->console_in,
816 CONFIG_CONSOLE_RECORD_IN_SIZE);
Simon Glass9854a872015-11-08 23:47:48 -0700817
818 return ret;
819}
820
821void console_record_reset(void)
822{
Heinrich Schuchardta3a9e042020-02-12 18:23:49 +0100823 membuff_purge((struct membuff *)&gd->console_out);
824 membuff_purge((struct membuff *)&gd->console_in);
Simon Glassc1a2bb42021-05-08 06:59:56 -0600825 gd->flags &= ~GD_FLG_RECORD_OVF;
Simon Glass9854a872015-11-08 23:47:48 -0700826}
827
Simon Glassbd347152020-07-28 19:41:11 -0600828int console_record_reset_enable(void)
Simon Glass9854a872015-11-08 23:47:48 -0700829{
830 console_record_reset();
831 gd->flags |= GD_FLG_RECORD;
Simon Glassbd347152020-07-28 19:41:11 -0600832
833 return 0;
Simon Glass9854a872015-11-08 23:47:48 -0700834}
Simon Glassb6123122020-01-27 08:49:54 -0700835
836int console_record_readline(char *str, int maxlen)
837{
Simon Glassc1a2bb42021-05-08 06:59:56 -0600838 if (gd->flags & GD_FLG_RECORD_OVF)
839 return -ENOSPC;
840
Heinrich Schuchardta3a9e042020-02-12 18:23:49 +0100841 return membuff_readline((struct membuff *)&gd->console_out, str,
842 maxlen, ' ');
Simon Glassb6123122020-01-27 08:49:54 -0700843}
844
845int console_record_avail(void)
846{
Heinrich Schuchardta3a9e042020-02-12 18:23:49 +0100847 return membuff_avail((struct membuff *)&gd->console_out);
Simon Glassb6123122020-01-27 08:49:54 -0700848}
849
Steffen Jaeckel25c8b9f2021-07-08 15:57:40 +0200850int console_in_puts(const char *str)
851{
852 return membuff_put((struct membuff *)&gd->console_in, str, strlen(str));
853}
854
Simon Glass9854a872015-11-08 23:47:48 -0700855#endif
856
wdenk47d1a6e2002-11-03 00:01:44 +0000857/* test if ctrl-c was pressed */
858static int ctrlc_disabled = 0; /* see disable_ctrl() */
859static int ctrlc_was_pressed = 0;
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100860int ctrlc(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000861{
wdenk47d1a6e2002-11-03 00:01:44 +0000862 if (!ctrlc_disabled && gd->have_console) {
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100863 if (tstc()) {
Heinrich Schuchardtc670aee2020-10-07 18:11:48 +0200864 switch (getchar()) {
wdenk47d1a6e2002-11-03 00:01:44 +0000865 case 0x03: /* ^C - Control C */
866 ctrlc_was_pressed = 1;
867 return 1;
868 default:
869 break;
870 }
871 }
872 }
Simon Glass8969ea32014-09-14 12:40:15 -0600873
wdenk47d1a6e2002-11-03 00:01:44 +0000874 return 0;
875}
Pierre Auberta5dffa42014-04-24 10:30:07 +0200876/* Reads user's confirmation.
877 Returns 1 if user's input is "y", "Y", "yes" or "YES"
878*/
879int confirm_yesno(void)
880{
881 int i;
882 char str_input[5];
wdenk47d1a6e2002-11-03 00:01:44 +0000883
Pierre Auberta5dffa42014-04-24 10:30:07 +0200884 /* Flush input */
885 while (tstc())
Heinrich Schuchardtc670aee2020-10-07 18:11:48 +0200886 getchar();
Pierre Auberta5dffa42014-04-24 10:30:07 +0200887 i = 0;
888 while (i < sizeof(str_input)) {
Heinrich Schuchardtc670aee2020-10-07 18:11:48 +0200889 str_input[i] = getchar();
Pierre Auberta5dffa42014-04-24 10:30:07 +0200890 putc(str_input[i]);
891 if (str_input[i] == '\r')
892 break;
893 i++;
894 }
895 putc('\n');
896 if (strncmp(str_input, "y\r", 2) == 0 ||
897 strncmp(str_input, "Y\r", 2) == 0 ||
898 strncmp(str_input, "yes\r", 4) == 0 ||
899 strncmp(str_input, "YES\r", 4) == 0)
900 return 1;
901 return 0;
902}
wdenk47d1a6e2002-11-03 00:01:44 +0000903/* pass 1 to disable ctrlc() checking, 0 to enable.
904 * returns previous state
905 */
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100906int disable_ctrlc(int disable)
wdenk47d1a6e2002-11-03 00:01:44 +0000907{
908 int prev = ctrlc_disabled; /* save previous state */
909
910 ctrlc_disabled = disable;
911 return prev;
912}
913
914int had_ctrlc (void)
915{
916 return ctrlc_was_pressed;
917}
918
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100919void clear_ctrlc(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000920{
921 ctrlc_was_pressed = 0;
922}
923
wdenk47d1a6e2002-11-03 00:01:44 +0000924/** U-Boot INIT FUNCTIONS *************************************************/
925
Andy Shevchenko32324872020-12-21 14:30:03 +0200926struct stdio_dev *console_search_dev(int flags, const char *name)
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200927{
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200928 struct stdio_dev *dev;
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200929
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200930 dev = stdio_get_by_name(name);
Simon Glassa2931b32016-02-06 14:31:37 -0700931#ifdef CONFIG_VIDCONSOLE_AS_LCD
Patrick Delaunay27b5b9e2020-07-01 14:56:10 +0200932 if (!dev && !strcmp(name, CONFIG_VIDCONSOLE_AS_NAME))
Simon Glassa2931b32016-02-06 14:31:37 -0700933 dev = stdio_get_by_name("vidconsole");
934#endif
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200935
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100936 if (dev && (dev->flags & flags))
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200937 return dev;
938
939 return NULL;
940}
941
Mike Frysingerd7be3052010-10-20 07:18:03 -0400942int console_assign(int file, const char *devname)
wdenk47d1a6e2002-11-03 00:01:44 +0000943{
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +0200944 int flag;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +0200945 struct stdio_dev *dev;
wdenk47d1a6e2002-11-03 00:01:44 +0000946
947 /* Check for valid file */
Andy Shevchenko7b9ca3f2021-02-11 17:09:37 +0200948 flag = stdio_file_to_flags(file);
949 if (flag < 0)
950 return flag;
wdenk47d1a6e2002-11-03 00:01:44 +0000951
952 /* Check for valid device name */
953
Andy Shevchenko32324872020-12-21 14:30:03 +0200954 dev = console_search_dev(flag, devname);
wdenk47d1a6e2002-11-03 00:01:44 +0000955
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100956 if (dev)
957 return console_setfile(file, dev);
wdenk47d1a6e2002-11-03 00:01:44 +0000958
959 return -1;
960}
961
Patrick Delaunay13551b92019-08-02 14:58:10 +0200962/* return true if the 'silent' flag is removed */
963static bool console_update_silent(void)
Chris Packham43e0a3d2016-09-23 15:59:43 +1200964{
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100965 unsigned long flags = gd->flags;
966
967 if (!IS_ENABLED(CONFIG_SILENT_CONSOLE))
968 return false;
969
Patrick Delaunay13551b92019-08-02 14:58:10 +0200970 if (env_get("silent")) {
Chris Packham43e0a3d2016-09-23 15:59:43 +1200971 gd->flags |= GD_FLG_SILENT;
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100972 return false;
Patrick Delaunay13551b92019-08-02 14:58:10 +0200973 }
Patrick Delaunay13551b92019-08-02 14:58:10 +0200974
Patrick Delaunayc04f8562020-12-18 12:46:43 +0100975 gd->flags &= ~GD_FLG_SILENT;
976
977 return !!(flags & GD_FLG_SILENT);
Chris Packham43e0a3d2016-09-23 15:59:43 +1200978}
979
Simon Glassb0895382017-06-15 21:37:50 -0600980int console_announce_r(void)
981{
982#if !CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
983 char buf[DISPLAY_OPTIONS_BANNER_LENGTH];
984
985 display_options_get_banner(false, buf, sizeof(buf));
986
Simon Glass493a4c82020-07-02 21:12:13 -0600987 console_puts_select(stdout, false, buf);
Simon Glassb0895382017-06-15 21:37:50 -0600988#endif
989
990 return 0;
991}
992
wdenk47d1a6e2002-11-03 00:01:44 +0000993/* Called before relocation - use serial functions */
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +0100994int console_init_f(void)
wdenk47d1a6e2002-11-03 00:01:44 +0000995{
wdenk47d1a6e2002-11-03 00:01:44 +0000996 gd->have_console = 1;
wdenkf72da342003-10-10 10:05:42 +0000997
Chris Packham43e0a3d2016-09-23 15:59:43 +1200998 console_update_silent();
wdenkf72da342003-10-10 10:05:42 +0000999
Siarhei Siamashka27669662015-01-08 09:02:31 +02001000 print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);
Graeme Russ9558b482011-09-01 00:48:27 +00001001
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +01001002 return 0;
wdenk47d1a6e2002-11-03 00:01:44 +00001003}
1004
Jean-Christophe PLAGNIOL-VILLARD7e3be7c2009-05-16 12:14:55 +02001005void stdio_print_current_devices(void)
1006{
Jean-Christophe PLAGNIOL-VILLARD7e3be7c2009-05-16 12:14:55 +02001007 /* Print information */
1008 puts("In: ");
1009 if (stdio_devices[stdin] == NULL) {
1010 puts("No input devices available!\n");
1011 } else {
1012 printf ("%s\n", stdio_devices[stdin]->name);
1013 }
1014
1015 puts("Out: ");
1016 if (stdio_devices[stdout] == NULL) {
1017 puts("No output devices available!\n");
1018 } else {
1019 printf ("%s\n", stdio_devices[stdout]->name);
1020 }
1021
1022 puts("Err: ");
1023 if (stdio_devices[stderr] == NULL) {
1024 puts("No error devices available!\n");
1025 } else {
1026 printf ("%s\n", stdio_devices[stderr]->name);
1027 }
Jean-Christophe PLAGNIOL-VILLARD7e3be7c2009-05-16 12:14:55 +02001028}
1029
Simon Glassb0265422017-01-16 07:03:26 -07001030#if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
wdenk47d1a6e2002-11-03 00:01:44 +00001031/* Called after the relocation - use desired console functions */
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +01001032int console_init_r(void)
wdenk47d1a6e2002-11-03 00:01:44 +00001033{
1034 char *stdinname, *stdoutname, *stderrname;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02001035 struct stdio_dev *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
wdenk6e592382004-04-18 17:39:38 +00001036 int i;
Gary Jennejohn16a28ef2008-11-06 15:04:23 +01001037 int iomux_err = 0;
Patrick Delaunay13551b92019-08-02 14:58:10 +02001038 int flushpoint;
wdenk47d1a6e2002-11-03 00:01:44 +00001039
Patrick Delaunaybf46be72019-08-02 14:58:09 +02001040 /* update silent for env loaded from flash (initr_env) */
Patrick Delaunay13551b92019-08-02 14:58:10 +02001041 if (console_update_silent())
1042 flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL;
1043 else
1044 flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL;
Patrick Delaunaybf46be72019-08-02 14:58:09 +02001045
wdenk47d1a6e2002-11-03 00:01:44 +00001046 /* set default handlers at first */
Martin Dorwig49cad542015-01-26 15:22:54 -07001047 gd->jt->getc = serial_getc;
1048 gd->jt->tstc = serial_tstc;
1049 gd->jt->putc = serial_putc;
1050 gd->jt->puts = serial_puts;
1051 gd->jt->printf = serial_printf;
wdenk47d1a6e2002-11-03 00:01:44 +00001052
1053 /* stdin stdout and stderr are in environment */
1054 /* scan for it */
Simon Glass00caae62017-08-03 12:22:12 -06001055 stdinname = env_get("stdin");
1056 stdoutname = env_get("stdout");
1057 stderrname = env_get("stderr");
wdenk47d1a6e2002-11-03 00:01:44 +00001058
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001059 if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */
Andy Shevchenko32324872020-12-21 14:30:03 +02001060 inputdev = console_search_dev(DEV_FLAGS_INPUT, stdinname);
1061 outputdev = console_search_dev(DEV_FLAGS_OUTPUT, stdoutname);
1062 errdev = console_search_dev(DEV_FLAGS_OUTPUT, stderrname);
Patrick Delaunayc04f8562020-12-18 12:46:43 +01001063 if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
1064 iomux_err = iomux_doenv(stdin, stdinname);
1065 iomux_err += iomux_doenv(stdout, stdoutname);
1066 iomux_err += iomux_doenv(stderr, stderrname);
1067 if (!iomux_err)
1068 /* Successful, so skip all the code below. */
1069 goto done;
1070 }
wdenk47d1a6e2002-11-03 00:01:44 +00001071 }
1072 /* if the devices are overwritten or not found, use default device */
1073 if (inputdev == NULL) {
Andy Shevchenko32324872020-12-21 14:30:03 +02001074 inputdev = console_search_dev(DEV_FLAGS_INPUT, "serial");
wdenk47d1a6e2002-11-03 00:01:44 +00001075 }
1076 if (outputdev == NULL) {
Andy Shevchenko32324872020-12-21 14:30:03 +02001077 outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
wdenk47d1a6e2002-11-03 00:01:44 +00001078 }
1079 if (errdev == NULL) {
Andy Shevchenko32324872020-12-21 14:30:03 +02001080 errdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
wdenk47d1a6e2002-11-03 00:01:44 +00001081 }
1082 /* Initializes output console first */
1083 if (outputdev != NULL) {
Gary Jennejohn16a28ef2008-11-06 15:04:23 +01001084 /* need to set a console if not done above. */
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +01001085 console_doenv(stdout, outputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001086 }
1087 if (errdev != NULL) {
Gary Jennejohn16a28ef2008-11-06 15:04:23 +01001088 /* need to set a console if not done above. */
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +01001089 console_doenv(stderr, errdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001090 }
1091 if (inputdev != NULL) {
Gary Jennejohn16a28ef2008-11-06 15:04:23 +01001092 /* need to set a console if not done above. */
Jean-Christophe PLAGNIOL-VILLARD5f032012009-02-01 17:07:52 +01001093 console_doenv(stdin, inputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001094 }
1095
Gary Jennejohn16a28ef2008-11-06 15:04:23 +01001096done:
Gary Jennejohn16a28ef2008-11-06 15:04:23 +01001097
Patrick Delaunayc04f8562020-12-18 12:46:43 +01001098 if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
1099 stdio_print_current_devices();
1100
Simon Glassa2931b32016-02-06 14:31:37 -07001101#ifdef CONFIG_VIDCONSOLE_AS_LCD
Patrick Delaunay27b5b9e2020-07-01 14:56:10 +02001102 if (strstr(stdoutname, CONFIG_VIDCONSOLE_AS_NAME))
Anatolij Gustschin22b897a2020-05-23 17:11:20 +02001103 printf("Warning: Please change '%s' to 'vidconsole' in stdout/stderr environment vars\n",
Patrick Delaunay27b5b9e2020-07-01 14:56:10 +02001104 CONFIG_VIDCONSOLE_AS_NAME);
Simon Glassa2931b32016-02-06 14:31:37 -07001105#endif
wdenk47d1a6e2002-11-03 00:01:44 +00001106
Patrick Delaunayc04f8562020-12-18 12:46:43 +01001107 if (IS_ENABLED(CONFIG_SYS_CONSOLE_ENV_OVERWRITE)) {
1108 /* set the environment variables (will overwrite previous env settings) */
1109 for (i = 0; i < MAX_FILES; i++)
1110 env_set(stdio_names[i], stdio_devices[i]->name);
wdenk47d1a6e2002-11-03 00:01:44 +00001111 }
wdenk47d1a6e2002-11-03 00:01:44 +00001112
Joe Hershbergerc4e00572012-12-11 22:16:19 -06001113 gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
1114
Patrick Delaunay13551b92019-08-02 14:58:10 +02001115 print_pre_console_buffer(flushpoint);
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +01001116 return 0;
wdenk47d1a6e2002-11-03 00:01:44 +00001117}
1118
Simon Glassb0265422017-01-16 07:03:26 -07001119#else /* !CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */
wdenk47d1a6e2002-11-03 00:01:44 +00001120
1121/* Called after the relocation - use desired console functions */
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +01001122int console_init_r(void)
wdenk47d1a6e2002-11-03 00:01:44 +00001123{
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02001124 struct stdio_dev *inputdev = NULL, *outputdev = NULL;
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +02001125 int i;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02001126 struct list_head *list = stdio_get_list();
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +02001127 struct list_head *pos;
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02001128 struct stdio_dev *dev;
Patrick Delaunay13551b92019-08-02 14:58:10 +02001129 int flushpoint;
wdenk47d1a6e2002-11-03 00:01:44 +00001130
Patrick Delaunaybf46be72019-08-02 14:58:09 +02001131 /* update silent for env loaded from flash (initr_env) */
Patrick Delaunay13551b92019-08-02 14:58:10 +02001132 if (console_update_silent())
1133 flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL;
1134 else
1135 flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL;
Chris Packham43e0a3d2016-09-23 15:59:43 +12001136
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +01001137 /*
1138 * suppress all output if splash screen is enabled and we have
Anatolij Gustschina7490812010-03-16 15:29:33 +01001139 * a bmp to display. We redirect the output from frame buffer
1140 * console to serial console in this case or suppress it if
1141 * "silent" mode was requested.
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +01001142 */
Patrick Delaunayc04f8562020-12-18 12:46:43 +01001143 if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) {
Anatolij Gustschina7490812010-03-16 15:29:33 +01001144 if (!(gd->flags & GD_FLG_SILENT))
Andy Shevchenko32324872020-12-21 14:30:03 +02001145 outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial");
Anatolij Gustschina7490812010-03-16 15:29:33 +01001146 }
wdenkf72da342003-10-10 10:05:42 +00001147
wdenk47d1a6e2002-11-03 00:01:44 +00001148 /* Scan devices looking for input and output devices */
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +02001149 list_for_each(pos, list) {
Jean-Christophe PLAGNIOL-VILLARD52cb4d42009-05-16 12:14:54 +02001150 dev = list_entry(pos, struct stdio_dev, list);
wdenk47d1a6e2002-11-03 00:01:44 +00001151
1152 if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
1153 inputdev = dev;
1154 }
1155 if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
1156 outputdev = dev;
1157 }
Jean-Christophe PLAGNIOL-VILLARDc1de7a62008-08-31 04:24:55 +02001158 if(inputdev && outputdev)
1159 break;
wdenk47d1a6e2002-11-03 00:01:44 +00001160 }
1161
1162 /* Initializes output console first */
1163 if (outputdev != NULL) {
Andy Shevchenko09d8f072021-02-11 17:09:39 +02001164 console_setfile_and_devices(stdout, outputdev);
1165 console_setfile_and_devices(stderr, outputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001166 }
1167
1168 /* Initializes input console */
Andy Shevchenko09d8f072021-02-11 17:09:39 +02001169 if (inputdev != NULL)
1170 console_setfile_and_devices(stdin, inputdev);
wdenk47d1a6e2002-11-03 00:01:44 +00001171
Patrick Delaunayc04f8562020-12-18 12:46:43 +01001172 if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
1173 stdio_print_current_devices();
wdenk47d1a6e2002-11-03 00:01:44 +00001174
1175 /* Setting environment variables */
Tom Rini27b42252018-05-03 09:12:26 -04001176 for (i = 0; i < MAX_FILES; i++) {
Simon Glass382bee52017-08-03 12:22:09 -06001177 env_set(stdio_names[i], stdio_devices[i]->name);
wdenk47d1a6e2002-11-03 00:01:44 +00001178 }
1179
Joe Hershbergerc4e00572012-12-11 22:16:19 -06001180 gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
1181
Patrick Delaunay13551b92019-08-02 14:58:10 +02001182 print_pre_console_buffer(flushpoint);
Jean-Christophe PLAGNIOL-VILLARDec6f1492009-02-01 17:07:51 +01001183 return 0;
wdenk47d1a6e2002-11-03 00:01:44 +00001184}
1185
Simon Glassb0265422017-01-16 07:03:26 -07001186#endif /* CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */