1/*	$NetBSD: console.c,v 1.2 2006/04/22 07:58:53 cherry Exp $	*/
2
3/*-
4 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30/* __FBSDID("$FreeBSD: src/sys/boot/common/console.c,v 1.6 2003/08/25 23:30:41 obrien Exp $"); */
31
32#include <lib/libsa/stand.h>
33#include <lib/libsa/loadfile.h>
34#include <lib/libkern/libkern.h>
35
36#include "bootstrap.h"
37/*
38 * Core console support
39 */
40
41static int	cons_set(struct env_var *ev, int flags, void *value);
42static int	cons_find(char *name);
43
44/*
45 * Detect possible console(s) to use.  The first probed console
46 * is marked active.  Also create the console variable.
47 *
48 * XXX Add logic for multiple console support.
49 */
50void
51cons_probe(void)
52{
53    int			cons;
54    int			active;
55    char		*prefconsole;
56
57    /* Do all console probes */
58    for (cons = 0; consoles[cons] != NULL; cons++) {
59	consoles[cons]->c_flags = 0;
60 	consoles[cons]->c_probe(consoles[cons]);
61    }
62    /* Now find the first working one */
63    active = -1;
64    for (cons = 0; consoles[cons] != NULL && active == -1; cons++) {
65	consoles[cons]->c_flags = 0;
66 	consoles[cons]->c_probe(consoles[cons]);
67	if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT))
68	    active = cons;
69    }
70
71    /* Check to see if a console preference has already been registered */
72    prefconsole = getenv("console");
73    if (prefconsole != NULL)
74	prefconsole = strdup(prefconsole);
75    if (prefconsole != NULL) {
76	unsetenv("console");		/* we want to replace this */
77	for (cons = 0; consoles[cons] != NULL; cons++)
78	    /* look for the nominated console, use it if it's functional */
79	    if (!strcmp(prefconsole, consoles[cons]->c_name) &&
80		(consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT)))
81		active = cons;
82	free(prefconsole);
83    }
84    if (active == -1)
85	active = 0;
86    consoles[active]->c_flags |= (C_ACTIVEIN | C_ACTIVEOUT);
87    consoles[active]->c_init(0);
88
89    printf("Console: %s\n", consoles[active]->c_desc);
90    env_setenv("console", EV_VOLATILE, consoles[active]->c_name, (ev_sethook_t *) cons_set,
91	env_nounset);
92}
93
94int
95getchar(void)
96{
97    int		cons;
98    int		rv;
99
100    /* Loop forever polling all active consoles */
101    for(;;)
102	for (cons = 0; consoles[cons] != NULL; cons++)
103	    if ((consoles[cons]->c_flags & C_ACTIVEIN) &&
104		((rv = consoles[cons]->c_in()) != -1))
105		return(rv);
106}
107
108int
109ischar(void)
110{
111    int		cons;
112
113    for (cons = 0; consoles[cons] != NULL; cons++)
114	if ((consoles[cons]->c_flags & C_ACTIVEIN) &&
115	    (consoles[cons]->c_ready() != 0))
116		return(1);
117    return(0);
118}
119
120void
121putchar(int c)
122{
123    int		cons;
124
125    /* Expand newlines */
126    if (c == '\n')
127	putchar('\r');
128
129    for (cons = 0; consoles[cons] != NULL; cons++)
130	if (consoles[cons]->c_flags & C_ACTIVEOUT)
131	    consoles[cons]->c_out(c);
132}
133
134static int
135cons_find(char *name)
136{
137    int		cons;
138
139    for (cons = 0; consoles[cons] != NULL; cons++)
140	if (!strcmp(consoles[cons]->c_name, name))
141	    return(cons);
142    return(-1);
143}
144
145
146/*
147 * Select a console.
148 *
149 * XXX Note that the console system design allows for some extension
150 *     here (eg. multiple consoles, input/output only, etc.)
151 */
152static int
153cons_set(struct env_var *ev, int flags, void *value)
154{
155    int		cons, active;
156
157    if ((value == NULL) || ((active = cons_find(value)) == -1)) {
158	if (value != NULL)
159	    printf("no such console '%s'\n", (char *)value);
160	printf("Available consoles:\n");
161	for (cons = 0; consoles[cons] != NULL; cons++)
162	    printf("    %s\n", consoles[cons]->c_name);
163	return(CMD_ERROR);
164    }
165
166    /* disable all current consoles */
167    for (cons = 0; consoles[cons] != NULL; cons++)
168	consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
169
170    /* enable selected console */
171    consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
172    consoles[active]->c_init(0);
173
174    env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
175    return(CMD_OK);
176}
177