xref: /openbmc/u-boot/common/console.c (revision c609719b)
1 /*
2  * (C) Copyright 2000
3  * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 #include <common.h>
25 #include <stdarg.h>
26 #include <malloc.h>
27 #include <console.h>
28 #include <syscall.h>
29 
30 void **syscall_tbl;
31 
32 #ifdef CFG_CONSOLE_IS_IN_ENV
33 /*
34  * if overwrite_console returns 1, the stdin, stderr and stdout
35  * are switched to the serial port, else the settings in the
36  * environment are used
37  */
38 #ifdef CFG_CONSOLE_OVERWRITE_ROUTINE
39 extern int overwrite_console (void);
40 #else
41 int overwrite_console (void)
42 {
43 	return (0);
44 }
45 #endif /* CFG_CONSOLE_OVERWRITE_ROUTINE */
46 
47 #endif /* CFG_CONSOLE_IS_IN_ENV */
48 
49 static int console_setfile (int file, device_t * dev)
50 {
51 	int error = 0;
52 
53 	if (dev == NULL)
54 		return -1;
55 
56 	switch (file) {
57 	case stdin:
58 	case stdout:
59 	case stderr:
60 		/* Start new device */
61 		if (dev->start) {
62 			error = dev->start ();
63 			/* If it's not started dont use it */
64 			if (error < 0)
65 				break;
66 		}
67 
68 		/* Assign the new device (leaving the existing one started) */
69 		stdio_devices[file] = dev;
70 
71 		/*
72 		 * Update monitor functions
73 		 * (to use the console stuff by other applications)
74 		 */
75 		switch (file) {
76 		case stdin:
77 			syscall_tbl[SYSCALL_GETC] = dev->getc;
78 			syscall_tbl[SYSCALL_TSTC] = dev->tstc;
79 			break;
80 		case stdout:
81 			syscall_tbl[SYSCALL_PUTC] = dev->putc;
82 			syscall_tbl[SYSCALL_PUTS] = dev->puts;
83 			syscall_tbl[SYSCALL_PRINTF] = printf;
84 			break;
85 		}
86 		break;
87 
88 	default:		/* Invalid file ID */
89 		error = -1;
90 	}
91 	return error;
92 }
93 
94 /** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/
95 
96 void serial_printf (const char *fmt, ...)
97 {
98 	va_list args;
99 	uint i;
100 	char printbuffer[CFG_PBSIZE];
101 
102 	va_start (args, fmt);
103 
104 	/* For this to work, printbuffer must be larger than
105 	 * anything we ever want to print.
106 	 */
107 	i = vsprintf (printbuffer, fmt, args);
108 	va_end (args);
109 
110 	serial_puts (printbuffer);
111 }
112 
113 int fgetc (int file)
114 {
115 	if (file < MAX_FILES)
116 		return stdio_devices[file]->getc ();
117 
118 	return -1;
119 }
120 
121 int ftstc (int file)
122 {
123 	if (file < MAX_FILES)
124 		return stdio_devices[file]->tstc ();
125 
126 	return -1;
127 }
128 
129 void fputc (int file, const char c)
130 {
131 	if (file < MAX_FILES)
132 		stdio_devices[file]->putc (c);
133 }
134 
135 void fputs (int file, const char *s)
136 {
137 	if (file < MAX_FILES)
138 		stdio_devices[file]->puts (s);
139 }
140 
141 void fprintf (int file, const char *fmt, ...)
142 {
143 	va_list args;
144 	uint i;
145 	char printbuffer[CFG_PBSIZE];
146 
147 	va_start (args, fmt);
148 
149 	/* For this to work, printbuffer must be larger than
150 	 * anything we ever want to print.
151 	 */
152 	i = vsprintf (printbuffer, fmt, args);
153 	va_end (args);
154 
155 	/* Send to desired file */
156 	fputs (file, printbuffer);
157 }
158 
159 /** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/
160 
161 int getc (void)
162 {
163 	DECLARE_GLOBAL_DATA_PTR;
164 
165 	if (gd->flags & GD_FLG_DEVINIT) {
166 		/* Get from the standard input */
167 		return fgetc (stdin);
168 	}
169 
170 	/* Send directly to the handler */
171 	return serial_getc ();
172 }
173 
174 int tstc (void)
175 {
176 	DECLARE_GLOBAL_DATA_PTR;
177 
178 	if (gd->flags & GD_FLG_DEVINIT) {
179 		/* Test the standard input */
180 		return ftstc (stdin);
181 	}
182 
183 	/* Send directly to the handler */
184 	return serial_tstc ();
185 }
186 
187 void putc (const char c)
188 {
189 	DECLARE_GLOBAL_DATA_PTR;
190 
191 	if (gd->flags & GD_FLG_DEVINIT) {
192 		/* Send to the standard output */
193 		fputc (stdout, c);
194 	} else {
195 		/* Send directly to the handler */
196 		serial_putc (c);
197 	}
198 }
199 
200 void puts (const char *s)
201 {
202 	DECLARE_GLOBAL_DATA_PTR;
203 
204 	if (gd->flags & GD_FLG_DEVINIT) {
205 		/* Send to the standard output */
206 		fputs (stdout, s);
207 	} else {
208 		/* Send directly to the handler */
209 		serial_puts (s);
210 	}
211 }
212 
213 void printf (const char *fmt, ...)
214 {
215 	va_list args;
216 	uint i;
217 	char printbuffer[CFG_PBSIZE];
218 
219 	va_start (args, fmt);
220 
221 	/* For this to work, printbuffer must be larger than
222 	 * anything we ever want to print.
223 	 */
224 	i = vsprintf (printbuffer, fmt, args);
225 	va_end (args);
226 
227 	/* Print the string */
228 	puts (printbuffer);
229 }
230 
231 /* test if ctrl-c was pressed */
232 static int ctrlc_disabled = 0;	/* see disable_ctrl() */
233 static int ctrlc_was_pressed = 0;
234 int ctrlc (void)
235 {
236 	DECLARE_GLOBAL_DATA_PTR;
237 
238 	if (!ctrlc_disabled && gd->have_console) {
239 		if (tstc ()) {
240 			switch (getc ()) {
241 			case 0x03:		/* ^C - Control C */
242 				ctrlc_was_pressed = 1;
243 				return 1;
244 			default:
245 				break;
246 			}
247 		}
248 	}
249 	return 0;
250 }
251 
252 /* pass 1 to disable ctrlc() checking, 0 to enable.
253  * returns previous state
254  */
255 int disable_ctrlc (int disable)
256 {
257 	int prev = ctrlc_disabled;	/* save previous state */
258 
259 	ctrlc_disabled = disable;
260 	return prev;
261 }
262 
263 int had_ctrlc (void)
264 {
265 	return ctrlc_was_pressed;
266 }
267 
268 void clear_ctrlc (void)
269 {
270 	ctrlc_was_pressed = 0;
271 }
272 
273 #ifdef CONFIG_MODEM_SUPPORT_DEBUG
274 char	screen[1024];
275 char *cursor = screen;
276 int once = 0;
277 inline void dbg(const char *fmt, ...)
278 {
279 	va_list	args;
280 	uint	i;
281 	char	printbuffer[CFG_PBSIZE];
282 
283 	if (!once) {
284 		memset(screen, 0, sizeof(screen));
285 		once++;
286 	}
287 
288 	va_start(args, fmt);
289 
290 	/* For this to work, printbuffer must be larger than
291 	 * anything we ever want to print.
292 	 */
293 	i = vsprintf(printbuffer, fmt, args);
294 	va_end(args);
295 
296 	if ((screen + sizeof(screen) - 1 - cursor) < strlen(printbuffer)+1) {
297 		memset(screen, 0, sizeof(screen));
298 		cursor = screen;
299 	}
300 	sprintf(cursor, printbuffer);
301 	cursor += strlen(printbuffer);
302 
303 }
304 #else
305 inline void dbg(const char *fmt, ...)
306 {
307 }
308 #endif
309 
310 /** U-Boot INIT FUNCTIONS *************************************************/
311 
312 int console_assign (int file, char *devname)
313 {
314 	int flag, i;
315 
316 	/* Check for valid file */
317 	switch (file) {
318 	case stdin:
319 		flag = DEV_FLAGS_INPUT;
320 		break;
321 	case stdout:
322 	case stderr:
323 		flag = DEV_FLAGS_OUTPUT;
324 		break;
325 	default:
326 		return -1;
327 	}
328 
329 	/* Check for valid device name */
330 
331 	for (i = 1; i <= ListNumItems (devlist); i++) {
332 		device_t *dev = ListGetPtrToItem (devlist, i);
333 
334 		if (strcmp (devname, dev->name) == 0) {
335 			if (dev->flags & flag)
336 				return console_setfile (file, dev);
337 
338 			return -1;
339 		}
340 	}
341 
342 	return -1;
343 }
344 
345 /* Called before relocation - use serial functions */
346 int console_init_f (void)
347 {
348 	DECLARE_GLOBAL_DATA_PTR;
349 
350 	gd->have_console = 1;
351 	return (0);
352 }
353 
354 #ifdef CFG_CONSOLE_IS_IN_ENV
355 /* search a device */
356 device_t *search_device (int flags, char *name)
357 {
358 	int i, items;
359 	device_t *dev = NULL;
360 
361 	items = ListNumItems (devlist);
362 	if (name == NULL)
363 		return dev;
364 
365 	for (i = 1; i <= items; i++) {
366 		dev = ListGetPtrToItem (devlist, i);
367 		if ((dev->flags & flags) && (strcmp (name, dev->name) == 0)) {
368 			break;
369 		}
370 	}
371 	return dev;
372 }
373 #endif /* CFG_CONSOLE_IS_IN_ENV */
374 
375 #ifdef CFG_CONSOLE_IS_IN_ENV
376 /* Called after the relocation - use desired console functions */
377 int console_init_r (void)
378 {
379 	char *stdinname, *stdoutname, *stderrname;
380 	device_t *inputdev = NULL, *outputdev = NULL, *errdev = NULL;
381 
382 	/* set default handlers at first */
383 	syscall_tbl[SYSCALL_GETC] = serial_getc;
384 	syscall_tbl[SYSCALL_TSTC] = serial_tstc;
385 	syscall_tbl[SYSCALL_PUTC] = serial_putc;
386 	syscall_tbl[SYSCALL_PUTS] = serial_puts;
387 	syscall_tbl[SYSCALL_PRINTF] = serial_printf;
388 
389 	/* stdin stdout and stderr are in environment */
390 	/* scan for it */
391 	stdinname  = getenv ("stdin");
392 	stdoutname = getenv ("stdout");
393 	stderrname = getenv ("stderr");
394 
395 	if (overwrite_console () == 0) { /* if not overwritten by config switch */
396 		inputdev  = search_device (DEV_FLAGS_INPUT,  stdinname);
397 		outputdev = search_device (DEV_FLAGS_OUTPUT, stdoutname);
398 		errdev    = search_device (DEV_FLAGS_OUTPUT, stderrname);
399 	}
400 	/* if the devices are overwritten or not found, use default device */
401 	if (inputdev == NULL) {
402 		inputdev  = search_device (DEV_FLAGS_INPUT,  "serial");
403 	}
404 	if (outputdev == NULL) {
405 		outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
406 	}
407 	if (errdev == NULL) {
408 		errdev    = search_device (DEV_FLAGS_OUTPUT, "serial");
409 	}
410 	/* Initializes output console first */
411 	if (outputdev != NULL) {
412 		console_setfile (stdout, outputdev);
413 	}
414 	if (errdev != NULL) {
415 		console_setfile (stderr, errdev);
416 	}
417 	if (inputdev != NULL) {
418 		console_setfile (stdin, inputdev);
419 	}
420 
421 #ifndef CFG_CONSOLE_INFO_QUIET
422 	/* Print information */
423 	printf ("In:    ");
424 	if (stdio_devices[stdin] == NULL) {
425 		printf ("No input devices available!\n");
426 	} else {
427 		printf ("%s\n", stdio_devices[stdin]->name);
428 	}
429 
430 	printf ("Out:   ");
431 	if (stdio_devices[stdout] == NULL) {
432 		printf ("No output devices available!\n");
433 	} else {
434 		printf ("%s\n", stdio_devices[stdout]->name);
435 	}
436 
437 	printf ("Err:   ");
438 	if (stdio_devices[stderr] == NULL) {
439 		printf ("No error devices available!\n");
440 	} else {
441 		printf ("%s\n", stdio_devices[stderr]->name);
442 	}
443 #endif /* CFG_CONSOLE_INFO_QUIET */
444 
445 #ifdef CFG_CONSOLE_ENV_OVERWRITE
446 	/* set the environment variables (will overwrite previous env settings) */
447 	for (i = 0; i < 3; i++) {
448 		setenv (stdio_names[i], stdio_devices[i]->name);
449 	}
450 #endif /*  CFG_CONSOLE_ENV_OVERWRITE */
451 
452 #if 0
453 	/* If nothing usable installed, use only the initial console */
454 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
455 		return (0);
456 #endif
457 	return (0);
458 }
459 
460 #else /* CFG_CONSOLE_IS_IN_ENV */
461 
462 /* Called after the relocation - use desired console functions */
463 int console_init_r (void)
464 {
465 	device_t *inputdev = NULL, *outputdev = NULL;
466 	int i, items = ListNumItems (devlist);
467 
468 	/* Scan devices looking for input and output devices */
469 	for (i = 1;
470 	     (i <= items) && ((inputdev == NULL) || (outputdev == NULL));
471 	     i++
472 	    ) {
473 		device_t *dev = ListGetPtrToItem (devlist, i);
474 
475 		if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
476 			inputdev = dev;
477 		}
478 		if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
479 			outputdev = dev;
480 		}
481 	}
482 
483 	/* Initializes output console first */
484 	if (outputdev != NULL) {
485 		console_setfile (stdout, outputdev);
486 		console_setfile (stderr, outputdev);
487 	}
488 
489 	/* Initializes input console */
490 	if (inputdev != NULL) {
491 		console_setfile (stdin, inputdev);
492 	}
493 
494 #ifndef CFG_CONSOLE_INFO_QUIET
495 	/* Print informations */
496 	printf ("In:    ");
497 	if (stdio_devices[stdin] == NULL) {
498 		printf ("No input devices available!\n");
499 	} else {
500 		printf ("%s\n", stdio_devices[stdin]->name);
501 	}
502 
503 	printf ("Out:   ");
504 	if (stdio_devices[stdout] == NULL) {
505 		printf ("No output devices available!\n");
506 	} else {
507 		printf ("%s\n", stdio_devices[stdout]->name);
508 	}
509 
510 	printf ("Err:   ");
511 	if (stdio_devices[stderr] == NULL) {
512 		printf ("No error devices available!\n");
513 	} else {
514 		printf ("%s\n", stdio_devices[stderr]->name);
515 	}
516 #endif /* CFG_CONSOLE_INFO_QUIET */
517 
518 	/* Setting environment variables */
519 	for (i = 0; i < 3; i++) {
520 		setenv (stdio_names[i], stdio_devices[i]->name);
521 	}
522 
523 #if 0
524 	/* If nothing usable installed, use only the initial console */
525 	if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
526 		return (0);
527 #endif
528 
529 	return (0);
530 }
531 
532 #endif /* CFG_CONSOLE_IS_IN_ENV */
533