Unleashed v1.4
[unleashed.git] / usr / src / boot / sys / boot / common / console.c
blob34488a886f547efefa56df2670b8cadeb191ce41
1 /*
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
27 #include <sys/cdefs.h>
29 #include <stand.h>
30 #include <string.h>
32 #include "bootstrap.h"
34 * Core console support
37 static int cons_set(struct env_var *ev, int flags, const void *value);
38 static int cons_find(const char *name);
39 static int cons_check(const char *string);
40 static int cons_change(const char *string);
41 static int twiddle_set(struct env_var *ev, int flags, const void *value);
44 * Detect possible console(s) to use. If preferred console(s) have been
45 * specified, mark them as active. Else, mark the first probed console
46 * as active. Also create the console variable.
48 void
49 cons_probe(void)
51 int cons;
52 int active;
53 char *prefconsole;
55 /* We want a callback to install the new value when this var changes. */
56 env_setenv("twiddle_divisor", EV_VOLATILE, "1", twiddle_set, env_nounset);
58 /* Do all console probes */
59 for (cons = 0; consoles[cons] != NULL; cons++) {
60 consoles[cons]->c_flags = 0;
61 consoles[cons]->c_probe(consoles[cons]);
63 /* Now find the first working one */
64 active = -1;
65 for (cons = 0; consoles[cons] != NULL && active == -1; cons++) {
66 consoles[cons]->c_flags = 0;
67 consoles[cons]->c_probe(consoles[cons]);
68 if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT))
69 active = cons;
71 /* Force a console even if all probes failed */
72 if (active == -1)
73 active = 0;
75 /* Check to see if a console preference has already been registered */
76 prefconsole = getenv("console");
77 if (prefconsole != NULL)
78 prefconsole = strdup(prefconsole);
79 if (prefconsole != NULL) {
80 unsetenv("console"); /* we want to replace this */
81 cons_change(prefconsole);
82 } else {
83 consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
84 consoles[active]->c_init(consoles[active], 0);
85 prefconsole = strdup(consoles[active]->c_name);
88 printf("Consoles: ");
89 for (cons = 0; consoles[cons] != NULL; cons++)
90 if (consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT))
91 printf("%s ", consoles[cons]->c_desc);
92 printf("\n");
94 if (prefconsole != NULL) {
95 env_setenv("console", EV_VOLATILE, prefconsole, cons_set,
96 env_nounset);
97 free(prefconsole);
101 void
102 cons_mode(int raw)
104 int cons;
106 for (cons = 0; consoles[cons] != NULL; cons++) {
107 if (raw == 0)
108 consoles[cons]->c_flags &= ~C_MODERAW;
109 else
110 consoles[cons]->c_flags |= C_MODERAW;
115 getchar(void)
117 int cons;
118 int flags = C_PRESENTIN | C_ACTIVEIN;
119 int rv;
122 * Loop forever polling all active consoles. Somewhat strangely,
123 * this code expects all ->c_in() implementations to effectively do an
124 * ischar() check first, returning -1 if there's not a char ready.
126 for(;;) {
127 for (cons = 0; consoles[cons] != NULL; cons++) {
128 if ((consoles[cons]->c_flags & flags) == flags &&
129 ((rv = consoles[cons]->c_in(consoles[cons])) != -1))
130 return(rv);
132 delay(30 * 1000); /* delay 30ms */
137 ischar(void)
139 int cons;
141 for (cons = 0; consoles[cons] != NULL; cons++)
142 if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) ==
143 (C_PRESENTIN | C_ACTIVEIN) &&
144 (consoles[cons]->c_ready(consoles[cons]) != 0))
145 return(1);
146 return(0);
149 void
150 putchar(int c)
152 int cons;
154 /* Expand newlines if not in raw mode */
155 for (cons = 0; consoles[cons] != NULL; cons++)
156 if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) ==
157 (C_PRESENTOUT | C_ACTIVEOUT)) {
158 if (c == '\n' && (consoles[cons]->c_flags & C_MODERAW) == 0)
159 consoles[cons]->c_out(consoles[cons], '\r');
160 consoles[cons]->c_out(consoles[cons], c);
165 * Find the console with the specified name.
167 static int
168 cons_find(const char *name)
170 int cons;
172 for (cons = 0; consoles[cons] != NULL; cons++)
173 if (!strcmp(consoles[cons]->c_name, name))
174 return (cons);
175 return (-1);
179 * Select one or more consoles.
181 static int
182 cons_set(struct env_var *ev, int flags, const void *value)
184 int ret;
186 if ((value == NULL) || (cons_check(value) == 0)) {
188 * Return CMD_OK instead of CMD_ERROR to prevent forth syntax error,
189 * which would prevent it processing any further loader.conf entries.
191 return (CMD_OK);
194 ret = cons_change(value);
195 if (ret != CMD_OK)
196 return (ret);
198 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
199 return (CMD_OK);
203 * Check that at least one the consoles listed in *string is valid
205 static int
206 cons_check(const char *string)
208 int cons, found, failed;
209 char *curpos, *dup, *next;
211 dup = next = strdup(string);
212 found = failed = 0;
213 while (next != NULL) {
214 curpos = strsep(&next, " ,");
215 if (*curpos != '\0') {
216 cons = cons_find(curpos);
217 if (cons == -1) {
218 printf("console %s is invalid!\n", curpos);
219 failed++;
220 } else {
221 found++;
226 free(dup);
228 if (found == 0)
229 printf("no valid consoles!\n");
231 if (found == 0 || failed != 0) {
232 printf("Available consoles:\n");
233 for (cons = 0; consoles[cons] != NULL; cons++)
234 printf(" %s\n", consoles[cons]->c_name);
237 return (found);
241 * Activate all the valid consoles listed in *string and disable all others.
243 static int
244 cons_change(const char *string)
246 int cons, active;
247 char *curpos, *dup, *next;
249 /* Disable all consoles */
250 for (cons = 0; consoles[cons] != NULL; cons++) {
251 consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
254 /* Enable selected consoles */
255 dup = next = strdup(string);
256 active = 0;
257 while (next != NULL) {
258 curpos = strsep(&next, " ,");
259 if (*curpos == '\0')
260 continue;
261 cons = cons_find(curpos);
262 if (cons >= 0) {
263 consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
264 consoles[cons]->c_init(consoles[cons], 0);
265 if ((consoles[cons]->c_flags & (C_PRESENTIN | C_PRESENTOUT)) ==
266 (C_PRESENTIN | C_PRESENTOUT)) {
267 active++;
268 continue;
271 if (active != 0) {
272 /* If no consoles have initialised we wouldn't see this. */
273 printf("console %s failed to initialize\n",
274 consoles[cons]->c_name);
279 free(dup);
281 if (active == 0) {
282 /* All requested consoles failed to initialise, try to recover. */
283 for (cons = 0; consoles[cons] != NULL; cons++) {
284 consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
285 consoles[cons]->c_init(consoles[cons], 0);
286 if ((consoles[cons]->c_flags &
287 (C_PRESENTIN | C_PRESENTOUT)) ==
288 (C_PRESENTIN | C_PRESENTOUT))
289 active++;
292 if (active == 0)
293 return (CMD_ERROR); /* Recovery failed. */
296 return (CMD_OK);
300 * Change the twiddle divisor.
302 * The user can set the twiddle_divisor variable to directly control how fast
303 * the progress twiddle spins, useful for folks with slow serial consoles. The
304 * code to monitor changes to the variable and propagate them to the twiddle
305 * routines has to live somewhere. Twiddling is console-related so it's here.
307 static int
308 twiddle_set(struct env_var *ev, int flags, const void *value)
310 u_long tdiv;
311 char * eptr;
313 tdiv = strtoul(value, &eptr, 0);
314 if (*(const char *)value == 0 || *eptr != 0) {
315 printf("invalid twiddle_divisor '%s'\n", (const char *)value);
316 return (CMD_ERROR);
318 twiddle_divisor((u_int)tdiv);
319 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
321 return(CMD_OK);