xref: /illumos-gate/usr/src/boot/common/console.c (revision 4ac2186d79f65de18b11f2693e78f73b27d5308b)
122028508SToomas Soome /*
222028508SToomas Soome  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
322028508SToomas Soome  * All rights reserved.
422028508SToomas Soome  *
522028508SToomas Soome  * Redistribution and use in source and binary forms, with or without
622028508SToomas Soome  * modification, are permitted provided that the following conditions
722028508SToomas Soome  * are met:
822028508SToomas Soome  * 1. Redistributions of source code must retain the above copyright
922028508SToomas Soome  *    notice, this list of conditions and the following disclaimer.
1022028508SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
1122028508SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
1222028508SToomas Soome  *    documentation and/or other materials provided with the distribution.
1322028508SToomas Soome  *
1422028508SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1522028508SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1622028508SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1722028508SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1822028508SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1922028508SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2022028508SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2122028508SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2222028508SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2322028508SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2422028508SToomas Soome  * SUCH DAMAGE.
2522028508SToomas Soome  */
2622028508SToomas Soome 
2722028508SToomas Soome #include <sys/cdefs.h>
2822028508SToomas Soome 
2922028508SToomas Soome #include <stand.h>
3022028508SToomas Soome #include <string.h>
3122028508SToomas Soome 
3222028508SToomas Soome #include "bootstrap.h"
3322028508SToomas Soome /*
3422028508SToomas Soome  * Core console support
3522028508SToomas Soome  */
3622028508SToomas Soome 
3722028508SToomas Soome static int	cons_set(struct env_var *ev, int flags, const void *value);
3822028508SToomas Soome static int	cons_find(const char *name);
3922028508SToomas Soome static int	cons_check(const char *string);
40f3ba9b4eSToomas Soome static int	cons_change(const char *string, char **);
4122028508SToomas Soome static int	twiddle_set(struct env_var *ev, int flags, const void *value);
4222028508SToomas Soome 
43b72c8d00SToomas Soome static int	last_input = -1;	/* input device index */
44b72c8d00SToomas Soome 
45b72c8d00SToomas Soome /*
46b72c8d00SToomas Soome  * With multiple active console devices, return index of last input
47b72c8d00SToomas Soome  * device, so we can set up os_console variable to denote console
48b72c8d00SToomas Soome  * device for kernel.
49b72c8d00SToomas Soome  *
50b72c8d00SToomas Soome  * Please note, this feature can not really work with UEFI, because
51b72c8d00SToomas Soome  * efi console input is returned from any device listed in ConIn,
52b72c8d00SToomas Soome  * and we have no way to check which device from ConIn actually was
53b72c8d00SToomas Soome  * generating input.
54b72c8d00SToomas Soome  */
55b72c8d00SToomas Soome int
cons_inputdev(void)56b72c8d00SToomas Soome cons_inputdev(void)
57b72c8d00SToomas Soome {
58b72c8d00SToomas Soome 	int	cons;
59b72c8d00SToomas Soome 	int	flags = C_PRESENTIN | C_ACTIVEIN;
60b72c8d00SToomas Soome 	int	active = 0;
61b72c8d00SToomas Soome 
62b72c8d00SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++)
63b72c8d00SToomas Soome 		if ((consoles[cons]->c_flags & flags) == flags)
64b72c8d00SToomas Soome 			active++;
65b72c8d00SToomas Soome 
66b72c8d00SToomas Soome 	/* With just one active console, we will not set os_console */
67b72c8d00SToomas Soome 	if (active == 1)
68b72c8d00SToomas Soome 		return (-1);
69b72c8d00SToomas Soome 
70b72c8d00SToomas Soome 	return (last_input);
71b72c8d00SToomas Soome }
72b72c8d00SToomas Soome 
7322028508SToomas Soome /*
74d3bd5503SToomas Soome  * Return number of array slots.
75d3bd5503SToomas Soome  */
76d3bd5503SToomas Soome uint_t
cons_array_size(void)77d3bd5503SToomas Soome cons_array_size(void)
78d3bd5503SToomas Soome {
79d3bd5503SToomas Soome 	uint_t n;
80d3bd5503SToomas Soome 
81d3bd5503SToomas Soome 	if (consoles == NULL)
82d3bd5503SToomas Soome 		return (0);
83d3bd5503SToomas Soome 
84d3bd5503SToomas Soome 	for (n = 0; consoles[n] != NULL; n++)
85d3bd5503SToomas Soome 		;
86d3bd5503SToomas Soome 	return (n + 1);
87d3bd5503SToomas Soome }
88d3bd5503SToomas Soome 
89*4ac2186dSToomas Soome struct console *
cons_get_console(const char * name)90*4ac2186dSToomas Soome cons_get_console(const char *name)
91*4ac2186dSToomas Soome {
92*4ac2186dSToomas Soome 	char port[5];
93*4ac2186dSToomas Soome 
94*4ac2186dSToomas Soome 	(void) strlcpy(port, name, sizeof (port));
95*4ac2186dSToomas Soome 	for (uint_t i = 0; consoles[i] != NULL; i++) {
96*4ac2186dSToomas Soome 		if (strcmp(port, consoles[i]->c_name) == 0)
97*4ac2186dSToomas Soome 			return (consoles[i]);
98*4ac2186dSToomas Soome 	}
99*4ac2186dSToomas Soome 
100*4ac2186dSToomas Soome 	printf("No such port: %s\n", port);
101*4ac2186dSToomas Soome 	return (NULL);
102*4ac2186dSToomas Soome }
103*4ac2186dSToomas Soome 
104d3bd5503SToomas Soome static void
cons_add_dev(struct console * dev)105d3bd5503SToomas Soome cons_add_dev(struct console *dev)
106d3bd5503SToomas Soome {
107d3bd5503SToomas Soome 	uint_t c = cons_array_size();
108d3bd5503SToomas Soome 	uint_t n = 1;
109d3bd5503SToomas Soome 	struct console **tmp;
110d3bd5503SToomas Soome 
111d3bd5503SToomas Soome 	if (c == 0)
112d3bd5503SToomas Soome 		n++;
113d3bd5503SToomas Soome 	tmp = realloc(consoles, (c + n) * sizeof (struct console *));
114d3bd5503SToomas Soome 	if (tmp == NULL)
115d3bd5503SToomas Soome 		return;
116d3bd5503SToomas Soome 	if (c > 0)
117d3bd5503SToomas Soome 		c--;
118d3bd5503SToomas Soome 	consoles = tmp;
119d3bd5503SToomas Soome 	consoles[c] = dev;
120d3bd5503SToomas Soome 	consoles[c + 1] = NULL;
121d3bd5503SToomas Soome }
122d3bd5503SToomas Soome 
123d3bd5503SToomas Soome /*
12422028508SToomas Soome  * Detect possible console(s) to use.  If preferred console(s) have been
12522028508SToomas Soome  * specified, mark them as active. Else, mark the first probed console
12622028508SToomas Soome  * as active.  Also create the console variable.
12722028508SToomas Soome  */
12822028508SToomas Soome void
cons_probe(void)12922028508SToomas Soome cons_probe(void)
13022028508SToomas Soome {
13122028508SToomas Soome 	int	cons;
13222028508SToomas Soome 	int	active;
133f3ba9b4eSToomas Soome 	char	*prefconsole, *list, *console;
13422028508SToomas Soome 
135d3bd5503SToomas Soome 	/* Build list of consoles */
136d3bd5503SToomas Soome 	consoles = NULL;
137d3bd5503SToomas Soome 	for (cons = 0;; cons++) {
138d3bd5503SToomas Soome 		if (ct_list[cons].ct_dev != NULL) {
139d3bd5503SToomas Soome 			cons_add_dev(ct_list[cons].ct_dev);
140d3bd5503SToomas Soome 			continue;
141d3bd5503SToomas Soome 		}
142d3bd5503SToomas Soome 		if (ct_list[cons].ct_init != NULL) {
143d3bd5503SToomas Soome 			ct_list[cons].ct_init();
144d3bd5503SToomas Soome 			continue;
145d3bd5503SToomas Soome 		}
146d3bd5503SToomas Soome 		break;
147d3bd5503SToomas Soome 	}
148d3bd5503SToomas Soome 
14922028508SToomas Soome 	/* We want a callback to install the new value when this var changes. */
150ae676b12SColin Percival 	(void) env_setenv("twiddle_divisor", EV_VOLATILE, "16", twiddle_set,
15122028508SToomas Soome 	    env_nounset);
15222028508SToomas Soome 
15322028508SToomas Soome 	/* Do all console probes */
15422028508SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++) {
15522028508SToomas Soome 		consoles[cons]->c_flags = 0;
15622028508SToomas Soome 		consoles[cons]->c_probe(consoles[cons]);
15722028508SToomas Soome 	}
15822028508SToomas Soome 	/* Now find the first working one */
15922028508SToomas Soome 	active = -1;
160f3ba9b4eSToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++) {
161f3ba9b4eSToomas Soome 		if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT)) {
16222028508SToomas Soome 			active = cons;
163f3ba9b4eSToomas Soome 			break;
16422028508SToomas Soome 		}
165f3ba9b4eSToomas Soome 	}
166f3ba9b4eSToomas Soome 
16722028508SToomas Soome 	/* Force a console even if all probes failed */
16822028508SToomas Soome 	if (active == -1)
16922028508SToomas Soome 		active = 0;
17022028508SToomas Soome 
17122028508SToomas Soome 	/* Check to see if a console preference has already been registered */
172f3ba9b4eSToomas Soome 	list = NULL;
17322028508SToomas Soome 	prefconsole = getenv("console");
17422028508SToomas Soome 	if (prefconsole != NULL)
17522028508SToomas Soome 		prefconsole = strdup(prefconsole);
176f3ba9b4eSToomas Soome 	if (prefconsole == NULL)
17722028508SToomas Soome 		prefconsole = strdup(consoles[active]->c_name);
178f3ba9b4eSToomas Soome 
179f3ba9b4eSToomas Soome 	/*
180f3ba9b4eSToomas Soome 	 * unset "console", we need to create one with callbacks.
181f3ba9b4eSToomas Soome 	 */
182f3ba9b4eSToomas Soome 	unsetenv("console");
183f3ba9b4eSToomas Soome 	cons_change(prefconsole, &list);
18422028508SToomas Soome 
18522028508SToomas Soome 	printf("Consoles: ");
18622028508SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++)
18722028508SToomas Soome 		if (consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT))
18822028508SToomas Soome 			printf("%s  ", consoles[cons]->c_desc);
18922028508SToomas Soome 	printf("\n");
19022028508SToomas Soome 
191f3ba9b4eSToomas Soome 	if (list != NULL)
192f3ba9b4eSToomas Soome 		console = list;
193f3ba9b4eSToomas Soome 	else
194f3ba9b4eSToomas Soome 		console = prefconsole;
195f3ba9b4eSToomas Soome 
196ae676b12SColin Percival 	(void) env_setenv("console", EV_VOLATILE, console, cons_set,
19722028508SToomas Soome 	    env_nounset);
198f3ba9b4eSToomas Soome 
19922028508SToomas Soome 	free(prefconsole);
200f3ba9b4eSToomas Soome 	free(list);
20122028508SToomas Soome }
20222028508SToomas Soome 
20322028508SToomas Soome void
cons_mode(int raw)20422028508SToomas Soome cons_mode(int raw)
20522028508SToomas Soome {
20622028508SToomas Soome 	int	cons;
20722028508SToomas Soome 
20822028508SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++) {
20922028508SToomas Soome 		if (raw == 0)
21022028508SToomas Soome 			consoles[cons]->c_flags &= ~C_MODERAW;
21122028508SToomas Soome 		else
21222028508SToomas Soome 			consoles[cons]->c_flags |= C_MODERAW;
21322028508SToomas Soome 	}
21422028508SToomas Soome }
21522028508SToomas Soome 
21622028508SToomas Soome int
getchar(void)21722028508SToomas Soome getchar(void)
21822028508SToomas Soome {
21922028508SToomas Soome 	int	cons;
22022028508SToomas Soome 	int	flags = C_PRESENTIN | C_ACTIVEIN;
22122028508SToomas Soome 	int	rv;
22222028508SToomas Soome 
22322028508SToomas Soome 	/*
22422028508SToomas Soome 	 * Loop forever polling all active consoles.  Somewhat strangely,
22522028508SToomas Soome 	 * this code expects all ->c_in() implementations to effectively do an
22622028508SToomas Soome 	 * ischar() check first, returning -1 if there's not a char ready.
22722028508SToomas Soome 	 */
22822028508SToomas Soome 	for (;;) {
22922028508SToomas Soome 		for (cons = 0; consoles[cons] != NULL; cons++) {
230b72c8d00SToomas Soome 			if ((consoles[cons]->c_flags & flags) == flags) {
231b72c8d00SToomas Soome 				rv = consoles[cons]->c_in(consoles[cons]);
232b72c8d00SToomas Soome 				if (rv != -1) {
233b72c8d00SToomas Soome #ifndef EFI
234b72c8d00SToomas Soome 					last_input = cons;
235b72c8d00SToomas Soome #endif
23622028508SToomas Soome 					return (rv);
23722028508SToomas Soome 				}
238b72c8d00SToomas Soome 			}
239b72c8d00SToomas Soome 		}
24022028508SToomas Soome 		delay(30 * 1000);	/* delay 30ms */
24122028508SToomas Soome 	}
24222028508SToomas Soome }
24322028508SToomas Soome 
24422028508SToomas Soome int
ischar(void)24522028508SToomas Soome ischar(void)
24622028508SToomas Soome {
24722028508SToomas Soome 	int	cons;
24822028508SToomas Soome 
24922028508SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++)
25022028508SToomas Soome 		if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) ==
25122028508SToomas Soome 		    (C_PRESENTIN | C_ACTIVEIN) &&
25222028508SToomas Soome 		    (consoles[cons]->c_ready(consoles[cons]) != 0))
25322028508SToomas Soome 			return (1);
25422028508SToomas Soome 	return (0);
25522028508SToomas Soome }
25622028508SToomas Soome 
25722028508SToomas Soome void
putchar(int c)25822028508SToomas Soome putchar(int c)
25922028508SToomas Soome {
26022028508SToomas Soome 	int	cons;
26122028508SToomas Soome 
26222028508SToomas Soome 	/* Expand newlines if not in raw mode */
26322028508SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++)
26422028508SToomas Soome 		if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) ==
26522028508SToomas Soome 		    (C_PRESENTOUT | C_ACTIVEOUT)) {
26622028508SToomas Soome 			if (c == '\n' &&
26722028508SToomas Soome 			    (consoles[cons]->c_flags & C_MODERAW) == 0)
26822028508SToomas Soome 				consoles[cons]->c_out(consoles[cons], '\r');
26922028508SToomas Soome 			consoles[cons]->c_out(consoles[cons], c);
27022028508SToomas Soome 		}
27122028508SToomas Soome }
27222028508SToomas Soome 
27322028508SToomas Soome /*
27422028508SToomas Soome  * Find the console with the specified name.
27522028508SToomas Soome  */
27622028508SToomas Soome static int
cons_find(const char * name)27722028508SToomas Soome cons_find(const char *name)
27822028508SToomas Soome {
27922028508SToomas Soome 	int	cons;
28022028508SToomas Soome 
28122028508SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++)
28222028508SToomas Soome 		if (strcmp(consoles[cons]->c_name, name) == 0)
28322028508SToomas Soome 			return (cons);
28422028508SToomas Soome 	return (-1);
28522028508SToomas Soome }
28622028508SToomas Soome 
28722028508SToomas Soome /*
28822028508SToomas Soome  * Select one or more consoles.
28922028508SToomas Soome  */
29022028508SToomas Soome static int
cons_set(struct env_var * ev,int flags,const void * value)29122028508SToomas Soome cons_set(struct env_var *ev, int flags, const void *value)
29222028508SToomas Soome {
293f3ba9b4eSToomas Soome 	int	ret;
294f3ba9b4eSToomas Soome 	char	*list;
29522028508SToomas Soome 
29622028508SToomas Soome 	if ((value == NULL) || (cons_check(value) == 0)) {
29722028508SToomas Soome 		/*
29822028508SToomas Soome 		 * Return CMD_OK instead of CMD_ERROR to prevent forth syntax
29922028508SToomas Soome 		 * error, which would prevent it processing any further
30022028508SToomas Soome 		 * loader.conf entries.
30122028508SToomas Soome 		 */
30222028508SToomas Soome 		return (CMD_OK);
30322028508SToomas Soome 	}
30422028508SToomas Soome 
305f3ba9b4eSToomas Soome 	list = NULL;
306f3ba9b4eSToomas Soome 	ret = cons_change(value, &list);
30722028508SToomas Soome 	if (ret != CMD_OK)
30822028508SToomas Soome 		return (ret);
30922028508SToomas Soome 
31022028508SToomas Soome 	/*
31122028508SToomas Soome 	 * set console variable.
31222028508SToomas Soome 	 */
31322028508SToomas Soome 	if (list != NULL) {
31422028508SToomas Soome 		(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, list,
31522028508SToomas Soome 		    NULL, NULL);
31622028508SToomas Soome 	} else {
31722028508SToomas Soome 		(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value,
31822028508SToomas Soome 		    NULL, NULL);
31922028508SToomas Soome 	}
32022028508SToomas Soome 	free(list);
321f3ba9b4eSToomas Soome 	return (ret);
32222028508SToomas Soome }
32322028508SToomas Soome 
32422028508SToomas Soome /*
32522028508SToomas Soome  * Check that at least one the consoles listed in *string is valid
32622028508SToomas Soome  */
32722028508SToomas Soome static int
cons_check(const char * string)32822028508SToomas Soome cons_check(const char *string)
32922028508SToomas Soome {
33022028508SToomas Soome 	int	cons, found, failed;
33122028508SToomas Soome 	char	*curpos, *dup, *next;
33222028508SToomas Soome 
33322028508SToomas Soome 	dup = next = strdup(string);
33422028508SToomas Soome 	found = failed = 0;
33522028508SToomas Soome 	while (next != NULL) {
33622028508SToomas Soome 		curpos = strsep(&next, " ,");
33722028508SToomas Soome 		if (*curpos != '\0') {
33822028508SToomas Soome 			cons = cons_find(curpos);
33922028508SToomas Soome 			if (cons == -1) {
34022028508SToomas Soome 				printf("console %s is invalid!\n", curpos);
34122028508SToomas Soome 				failed++;
34222028508SToomas Soome 			} else {
34322028508SToomas Soome 				if ((consoles[cons]->c_flags &
34422028508SToomas Soome 				    (C_PRESENTIN | C_PRESENTOUT)) !=
34522028508SToomas Soome 				    (C_PRESENTIN | C_PRESENTOUT)) {
34622028508SToomas Soome 					failed++;
34722028508SToomas Soome 				} else
34822028508SToomas Soome 					found++;
34922028508SToomas Soome 			}
35022028508SToomas Soome 		}
35122028508SToomas Soome 	}
35222028508SToomas Soome 
35322028508SToomas Soome 	free(dup);
35422028508SToomas Soome 
35522028508SToomas Soome 	if (found == 0)
35622028508SToomas Soome 		printf("no valid consoles!\n");
35722028508SToomas Soome 
35822028508SToomas Soome 	if (found == 0 || failed != 0) {
35922028508SToomas Soome 		printf("Available consoles:\n");
36022028508SToomas Soome 		for (cons = 0; consoles[cons] != NULL; cons++) {
36122028508SToomas Soome 			printf("    %s", consoles[cons]->c_name);
36222028508SToomas Soome 			if (consoles[cons]->c_devinfo != NULL)
36322028508SToomas Soome 				consoles[cons]->c_devinfo(consoles[cons]);
36422028508SToomas Soome 			printf("\n");
36522028508SToomas Soome 		}
36622028508SToomas Soome 	}
36722028508SToomas Soome 
36822028508SToomas Soome 	return (found);
36922028508SToomas Soome }
37022028508SToomas Soome 
371f3ba9b4eSToomas Soome /*
372f3ba9b4eSToomas Soome  * Helper function to build string with list of console names.
373f3ba9b4eSToomas Soome  */
374f3ba9b4eSToomas Soome static char *
cons_add_list(char * list,const char * value)375f3ba9b4eSToomas Soome cons_add_list(char *list, const char *value)
376f3ba9b4eSToomas Soome {
377f3ba9b4eSToomas Soome 	char *tmp;
378f3ba9b4eSToomas Soome 
379f3ba9b4eSToomas Soome 	if (list == NULL)
380f3ba9b4eSToomas Soome 		return (strdup(value));
381f3ba9b4eSToomas Soome 
382f3ba9b4eSToomas Soome 	if (asprintf(&tmp, "%s,%s", list, value) > 0) {
383f3ba9b4eSToomas Soome 		free(list);
384f3ba9b4eSToomas Soome 		list = tmp;
385f3ba9b4eSToomas Soome 	}
386f3ba9b4eSToomas Soome 	return (list);
387f3ba9b4eSToomas Soome }
38822028508SToomas Soome 
38922028508SToomas Soome /*
390f3ba9b4eSToomas Soome  * Activate all the valid consoles listed in string and disable all others.
391f3ba9b4eSToomas Soome  * Return comma separated string with list of activated console names.
39222028508SToomas Soome  */
39322028508SToomas Soome static int
cons_change(const char * string,char ** list)394f3ba9b4eSToomas Soome cons_change(const char *string, char **list)
39522028508SToomas Soome {
396f3ba9b4eSToomas Soome 	int	cons, active, rv;
39722028508SToomas Soome 	char	*curpos, *dup, *next;
39822028508SToomas Soome 
39922028508SToomas Soome 	/* Disable all consoles */
40022028508SToomas Soome 	for (cons = 0; consoles[cons] != NULL; cons++) {
40122028508SToomas Soome 		consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
40222028508SToomas Soome 	}
40322028508SToomas Soome 
40422028508SToomas Soome 	/* Enable selected consoles */
40522028508SToomas Soome 	dup = next = strdup(string);
40622028508SToomas Soome 	active = 0;
407f3ba9b4eSToomas Soome 	*list = NULL;
408f3ba9b4eSToomas Soome 	rv = CMD_OK;
40922028508SToomas Soome 	while (next != NULL) {
41022028508SToomas Soome 		curpos = strsep(&next, " ,");
41122028508SToomas Soome 		if (*curpos == '\0')
41222028508SToomas Soome 			continue;
41322028508SToomas Soome 		cons = cons_find(curpos);
41422028508SToomas Soome 		if (cons >= 0) {
41522028508SToomas Soome 			consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
41622028508SToomas Soome 			consoles[cons]->c_init(consoles[cons], 0);
41722028508SToomas Soome 			if ((consoles[cons]->c_flags &
41822028508SToomas Soome 			    (C_ACTIVEIN | C_ACTIVEOUT)) ==
41922028508SToomas Soome 			    (C_ACTIVEIN | C_ACTIVEOUT)) {
42022028508SToomas Soome 				active++;
421f3ba9b4eSToomas Soome 				*list = cons_add_list(*list, curpos);
42222028508SToomas Soome 				continue;
42322028508SToomas Soome 			}
42422028508SToomas Soome 
42522028508SToomas Soome 			if (active != 0) {
42622028508SToomas Soome 				/*
42722028508SToomas Soome 				 * If no consoles have initialised we wouldn't
42822028508SToomas Soome 				 * see this.
42922028508SToomas Soome 				 */
43022028508SToomas Soome 				printf("console %s failed to initialize\n",
43122028508SToomas Soome 				    consoles[cons]->c_name);
43222028508SToomas Soome 			}
43322028508SToomas Soome 		}
43422028508SToomas Soome 	}
43522028508SToomas Soome 
43622028508SToomas Soome 	free(dup);
43722028508SToomas Soome 
43822028508SToomas Soome 	if (active == 0) {
43922028508SToomas Soome 		/*
44022028508SToomas Soome 		 * All requested consoles failed to initialise, try to recover.
44122028508SToomas Soome 		 */
44222028508SToomas Soome 		for (cons = 0; consoles[cons] != NULL; cons++) {
44322028508SToomas Soome 			consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
44422028508SToomas Soome 			consoles[cons]->c_init(consoles[cons], 0);
44522028508SToomas Soome 			if ((consoles[cons]->c_flags &
44622028508SToomas Soome 			    (C_ACTIVEIN | C_ACTIVEOUT)) ==
447f3ba9b4eSToomas Soome 			    (C_ACTIVEIN | C_ACTIVEOUT)) {
44822028508SToomas Soome 				active++;
449f3ba9b4eSToomas Soome 				*list = cons_add_list(*list,
450f3ba9b4eSToomas Soome 				    consoles[cons]->c_name);
451f3ba9b4eSToomas Soome 			}
45222028508SToomas Soome 		}
45322028508SToomas Soome 
45422028508SToomas Soome 		if (active == 0)
455f3ba9b4eSToomas Soome 			rv = CMD_ERROR; /* Recovery failed. */
45622028508SToomas Soome 	}
45722028508SToomas Soome 
458f3ba9b4eSToomas Soome 	return (rv);
45922028508SToomas Soome }
46022028508SToomas Soome 
46122028508SToomas Soome /*
46222028508SToomas Soome  * Change the twiddle divisor.
46322028508SToomas Soome  *
46422028508SToomas Soome  * The user can set the twiddle_divisor variable to directly control how fast
46522028508SToomas Soome  * the progress twiddle spins, useful for folks with slow serial consoles.  The
46622028508SToomas Soome  * code to monitor changes to the variable and propagate them to the twiddle
46722028508SToomas Soome  * routines has to live somewhere.  Twiddling is console-related so it's here.
46822028508SToomas Soome  */
46922028508SToomas Soome static int
twiddle_set(struct env_var * ev,int flags,const void * value)47022028508SToomas Soome twiddle_set(struct env_var *ev, int flags, const void *value)
47122028508SToomas Soome {
47222028508SToomas Soome 	ulong_t tdiv;
47322028508SToomas Soome 	char *eptr;
47422028508SToomas Soome 
47522028508SToomas Soome 	tdiv = strtoul(value, &eptr, 0);
47622028508SToomas Soome 	if (*(const char *)value == 0 || *eptr != 0) {
47722028508SToomas Soome 		printf("invalid twiddle_divisor '%s'\n", (const char *)value);
47822028508SToomas Soome 		return (CMD_ERROR);
47922028508SToomas Soome 	}
48022028508SToomas Soome 	twiddle_divisor((uint_t)tdiv);
481ae676b12SColin Percival 	(void) env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
48222028508SToomas Soome 
48322028508SToomas Soome 	return (CMD_OK);
48422028508SToomas Soome }
48522028508SToomas Soome 
48622028508SToomas Soome COMMAND_SET(console, "console", "console info", command_console);
48722028508SToomas Soome 
48822028508SToomas Soome static int
command_console(int argc,char * argv[])48922028508SToomas Soome command_console(int argc, char *argv[])
49022028508SToomas Soome {
49122028508SToomas Soome 	if (argc > 1)
49222028508SToomas Soome 		printf("%s: list info about available consoles\n", argv[0]);
49322028508SToomas Soome 
49422028508SToomas Soome 	printf("Current console: %s\n", getenv("console"));
49522028508SToomas Soome 	printf("Available consoles:\n");
49622028508SToomas Soome 	for (int cons = 0; consoles[cons] != NULL; cons++) {
49722028508SToomas Soome 		printf("    %s", consoles[cons]->c_name);
49822028508SToomas Soome 		if (consoles[cons]->c_devinfo != NULL)
49922028508SToomas Soome 			consoles[cons]->c_devinfo(consoles[cons]);
50022028508SToomas Soome 		printf("\n");
50122028508SToomas Soome 	}
50222028508SToomas Soome 
50322028508SToomas Soome 	return (CMD_OK);
50422028508SToomas Soome }
505