1 /*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
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.
13 *
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.
25 *
26 * $FreeBSD: src/sys/boot/common/console.c,v 1.6 2003/08/25 23:30:41 obrien Exp $
27 * $DragonFly: src/sys/boot/common/console.c,v 1.5 2004/06/26 02:26:20 dillon Exp $
28 */
29
30 #include <stand.h>
31 #include <string.h>
32
33 #include "bootstrap.h"
34 /*
35 * Core console support
36 */
37
38 static int cons_set(struct env_var *ev, int flags, const void *value);
39 static int cons_find(const char *name);
40
41 /*
42 * Detect possible console(s) to use. The first probed console
43 * is marked active. Also create the console variable.
44 *
45 * XXX Add logic for multiple console support.
46 */
47 void
cons_probe(void)48 cons_probe(void)
49 {
50 int cons;
51 int active;
52 char *prefconsole;
53
54 /*
55 * Probe all available consoles
56 */
57 for (cons = 0; consoles[cons] != NULL; cons++) {
58 consoles[cons]->c_flags = 0;
59 consoles[cons]->c_probe(consoles[cons]);
60 }
61
62 /*
63 * Get our console preference. If there is no preference, all
64 * available consoles will be made active in parallel. Otherwise
65 * only the specified console is activated.
66 */
67 active = -1;
68 if ((prefconsole = getenv("console")) != NULL) {
69 for (cons = 0; consoles[cons] != NULL; cons++) {
70 if (strcmp(prefconsole, consoles[cons]->c_name) == 0) {
71 if (consoles[cons]->c_flags & (C_PRESENTIN | C_PRESENTOUT))
72 active = cons;
73 }
74 }
75 unsetenv("console");
76 if (active >= 0) {
77 env_setenv("console", EV_VOLATILE, consoles[active]->c_name,
78 cons_set, env_nounset);
79 }
80 }
81
82 /*
83 * Active the active console or all consoles if active is -1.
84 */
85 for (cons = 0; consoles[cons] != NULL; cons++) {
86 if ((active == -1 || cons == active) &&
87 (consoles[cons]->c_flags & (C_PRESENTIN|C_PRESENTOUT))
88 ) {
89 consoles[cons]->c_flags |= (C_ACTIVEIN | C_ACTIVEOUT);
90 consoles[cons]->c_init(0);
91 printf("Console: %s\n", consoles[cons]->c_desc);
92 }
93 }
94 }
95
96 int
getchar(void)97 getchar(void)
98 {
99 int cons;
100 int rv;
101
102 /* Loop forever polling all active consoles */
103 for(;;) {
104 for (cons = 0; consoles[cons] != NULL; cons++) {
105 if ((consoles[cons]->c_flags & C_ACTIVEIN) &&
106 ((rv = consoles[cons]->c_in()) != -1)
107 ) {
108 return(rv);
109 }
110 }
111 }
112 }
113
114 int
ischar(void)115 ischar(void)
116 {
117 int cons;
118
119 for (cons = 0; consoles[cons] != NULL; cons++)
120 if ((consoles[cons]->c_flags & C_ACTIVEIN) &&
121 (consoles[cons]->c_ready() != 0))
122 return(1);
123 return(0);
124 }
125
126 #ifdef COMCONSOLE_DEBUG
127
128 static int
isa_inb(int port)129 isa_inb(int port)
130 {
131 u_char data;
132
133 if (__builtin_constant_p(port) &&
134 (((port) & 0xffff) < 0x100) &&
135 ((port) < 0x10000)) {
136 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
137 } else {
138 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
139 }
140 return(data);
141 }
142
143 static void
isa_outb(int port,int value)144 isa_outb(int port, int value)
145 {
146 u_char al = value;
147
148 if (__builtin_constant_p(port) &&
149 (((port) & 0xffff) < 0x100) &&
150 ((port) < 0x10000)) {
151 __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port)));
152 } else {
153 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
154 }
155 }
156
157 #endif
158
159 void
putchar(int c)160 putchar(int c)
161 {
162 int cons;
163
164 #ifdef COMCONSOLE_DEBUG
165 if ((consoles[1]->c_flags & C_ACTIVEOUT) == 0) {
166 while ((isa_inb(0x3f8+5) & 0x20) == 0) /* wait tx ready */
167 ;
168 isa_outb(0x3f8, c); /* output */
169 }
170 #endif
171
172 /* Expand newlines */
173 if (c == '\n')
174 putchar('\r');
175
176 for (cons = 0; consoles[cons] != NULL; cons++) {
177 if (consoles[cons]->c_flags & C_ACTIVEOUT)
178 consoles[cons]->c_out(c);
179 }
180 }
181
182 static int
cons_find(const char * name)183 cons_find(const char *name)
184 {
185 int cons;
186
187 for (cons = 0; consoles[cons] != NULL; cons++)
188 if (!strcmp(consoles[cons]->c_name, name))
189 return(cons);
190 return(-1);
191 }
192
193
194 /*
195 * Select a console.
196 *
197 * XXX Note that the console system design allows for some extension
198 * here (eg. multiple consoles, input/output only, etc.)
199 */
200 static int
cons_set(struct env_var * ev,int flags,const void * value)201 cons_set(struct env_var *ev, int flags, const void *value)
202 {
203 int cons, active;
204
205 if ((value == NULL) || ((active = cons_find(value)) == -1)) {
206 if (value != NULL)
207 printf("no such console '%s'\n", (char *)value);
208 printf("Available consoles:\n");
209 for (cons = 0; consoles[cons] != NULL; cons++)
210 printf(" %s\n", consoles[cons]->c_name);
211 return(CMD_ERROR);
212 }
213
214 /* disable all current consoles */
215 for (cons = 0; consoles[cons] != NULL; cons++)
216 consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
217
218 /* enable selected console */
219 consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
220 consoles[active]->c_init(0);
221
222 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
223 return(CMD_OK);
224 }
225