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 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 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 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 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 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 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 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 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