1 /*- 2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) 3 * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <stand.h> 34 #include <bootstrap.h> 35 #include <btxv86.h> 36 #include <machine/psl.h> 37 #include <machine/cpufunc.h> 38 #include <teken.h> 39 #include <stdbool.h> 40 41 #include <dev/vt/hw/vga/vt_vga_reg.h> 42 43 #include "libi386.h" 44 45 #if KEYBOARD_PROBE 46 static int probe_keyboard(void); 47 #endif 48 static void vidc_probe(struct console *cp); 49 static int vidc_init(int arg); 50 static void vidc_putchar(int c); 51 static int vidc_getchar(void); 52 static int vidc_ischar(void); 53 54 static int vidc_started; 55 static uint16_t *vgatext; 56 57 static tf_bell_t vidc_cons_bell; 58 static tf_cursor_t vidc_text_cursor; 59 static tf_putchar_t vidc_text_putchar; 60 static tf_fill_t vidc_text_fill; 61 static tf_copy_t vidc_text_copy; 62 static tf_param_t vidc_text_param; 63 static tf_respond_t vidc_cons_respond; 64 65 static teken_funcs_t tf = { 66 .tf_bell = vidc_cons_bell, 67 .tf_cursor = vidc_text_cursor, 68 .tf_putchar = vidc_text_putchar, 69 .tf_fill = vidc_text_fill, 70 .tf_copy = vidc_text_copy, 71 .tf_param = vidc_text_param, 72 .tf_respond = vidc_cons_respond, 73 }; 74 75 teken_t teken; 76 teken_pos_t tp; 77 78 struct text_pixel { 79 teken_char_t c; 80 teken_attr_t a; 81 }; 82 83 static struct text_pixel *buffer; 84 85 #define NCOLORS 16 86 87 /* 88 * Between console's palette and VGA's one: 89 * - blue and red are swapped (1 <-> 4) 90 * - yellow and cyan are swapped (3 <-> 6) 91 */ 92 static const int cons_to_vga_colors[NCOLORS] = { 93 0, 4, 2, 6, 1, 5, 3, 7, 94 8, 12, 10, 14, 9, 13, 11, 15 95 }; 96 97 #define TEXT_COLS 80 98 #define TEXT_ROWS 25 99 #define KEYBUFSZ 10 100 101 static uint8_t keybuf[KEYBUFSZ]; /* keybuf for extended codes */ 102 103 struct console vidconsole = { 104 .c_name = "vidconsole", 105 .c_desc = "internal video/keyboard", 106 .c_flags = 0, 107 .c_probe = vidc_probe, 108 .c_init = vidc_init, 109 .c_out = vidc_putchar, 110 .c_in = vidc_getchar, 111 .c_ready = vidc_ischar 112 }; 113 114 static int 115 vga_get_reg(int reg, int index) 116 { 117 return (inb(reg + index)); 118 } 119 120 static int 121 vga_get_atr(int reg, int i) 122 { 123 int ret; 124 125 (void) inb(reg + VGA_GEN_INPUT_STAT_1); 126 outb(reg + VGA_AC_WRITE, i); 127 ret = inb(reg + VGA_AC_READ); 128 129 (void) inb(reg + VGA_GEN_INPUT_STAT_1); 130 131 return (ret); 132 } 133 134 static void 135 vga_set_atr(int reg, int i, int v) 136 { 137 (void) inb(reg + VGA_GEN_INPUT_STAT_1); 138 outb(reg + VGA_AC_WRITE, i); 139 outb(reg + VGA_AC_WRITE, v); 140 141 (void) inb(reg + VGA_GEN_INPUT_STAT_1); 142 } 143 144 static void 145 vga_set_indexed(int reg, int indexreg, int datareg, uint8_t index, uint8_t val) 146 { 147 outb(reg + indexreg, index); 148 outb(reg + datareg, val); 149 } 150 151 static int 152 vga_get_indexed(int reg, int indexreg, int datareg, uint8_t index) 153 { 154 outb(reg + indexreg, index); 155 return (inb(reg + datareg)); 156 } 157 158 static int 159 vga_get_crtc(int reg, int i) 160 { 161 return (vga_get_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i)); 162 } 163 164 static void 165 vga_set_crtc(int reg, int i, int v) 166 { 167 vga_set_indexed(reg, VGA_CRTC_ADDRESS, VGA_CRTC_DATA, i, v); 168 } 169 170 static void 171 vidc_text_set_cursor(teken_unit_t row, teken_unit_t col, bool visible) 172 { 173 uint16_t addr; 174 uint8_t msl, s, e; 175 176 msl = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_MAX_SCAN_LINE) & 0x1f; 177 s = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_START) & 0xC0; 178 e = vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_END); 179 180 if (visible == true) { 181 addr = row * TEXT_COLS + col; 182 vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_HIGH, addr >> 8); 183 vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_LOW, 184 addr & 0xff); 185 e = msl; 186 } else { 187 s |= (1<<5); 188 } 189 vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_START, s); 190 vga_set_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_END, e); 191 } 192 193 static void 194 vidc_text_get_cursor(teken_unit_t *row, teken_unit_t *col) 195 { 196 uint16_t addr; 197 198 addr = (vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_HIGH) << 8) + 199 vga_get_crtc(VGA_REG_BASE, VGA_CRTC_CURSOR_LOC_LOW); 200 201 *row = addr / TEXT_COLS; 202 *col = addr % TEXT_COLS; 203 } 204 205 /* 206 * Not implemented. 207 */ 208 static void 209 vidc_cons_bell(void *s __unused) 210 { 211 } 212 213 static void 214 vidc_text_cursor(void *s __unused, const teken_pos_t *p) 215 { 216 teken_unit_t row, col; 217 218 if (p->tp_col == TEXT_COLS) 219 col = p->tp_col - 1; 220 else 221 col = p->tp_col; 222 223 if (p->tp_row == TEXT_ROWS) 224 row = p->tp_row - 1; 225 else 226 row = p->tp_row; 227 228 vidc_text_set_cursor(row, col, true); 229 } 230 231 /* 232 * Binary searchable table for Unicode to CP437 conversion. 233 */ 234 struct unicp437 { 235 uint16_t unicode_base; 236 uint8_t cp437_base; 237 uint8_t length; 238 }; 239 240 static const struct unicp437 cp437table[] = { 241 { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, 242 { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, 243 { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, 244 { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, 245 { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, 246 { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, 247 { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, 248 { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, 249 { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, 250 { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, 251 { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 }, 252 { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 }, 253 { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 }, 254 { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 }, 255 { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, 256 { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, 257 { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, 258 { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, 259 { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, 260 { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, 261 { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, 262 { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, 263 { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, 264 { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, 265 { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, 266 { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, 267 { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, 268 { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, 269 { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, 270 { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, 271 { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, 272 { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, 273 { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, 274 { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, 275 { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, 276 { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, 277 { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, 278 { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, 279 { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, 280 { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, 281 { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, 282 { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, 283 { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, 284 { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, 285 { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, 286 { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, 287 { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, 288 { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, 289 { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, 290 { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, 291 { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, 292 { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, 293 { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, 294 { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, 295 { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, 296 { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, 297 { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, 298 { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, 299 { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, 300 { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, 301 { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, 302 { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, 303 { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, 304 { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, 305 { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, 306 { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, 307 { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, 308 { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, 309 { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, 310 { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, 311 { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, 312 { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, 313 { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, 314 { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, 315 { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, 316 { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, 317 { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 }, 318 { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, 319 { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, 320 { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, 321 { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, 322 { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, 323 { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, 324 { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x00 }, 325 { 0x266c, 0x0e, 0x00 } 326 }; 327 328 static uint8_t 329 vga_get_cp437(teken_char_t c) 330 { 331 int min, mid, max; 332 333 min = 0; 334 max = (sizeof(cp437table) / sizeof(struct unicp437)) - 1; 335 336 if (c < cp437table[0].unicode_base || 337 c > cp437table[max].unicode_base + cp437table[max].length) 338 return ('?'); 339 340 while (max >= min) { 341 mid = (min + max) / 2; 342 if (c < cp437table[mid].unicode_base) 343 max = mid - 1; 344 else if (c > cp437table[mid].unicode_base + 345 cp437table[mid].length) 346 min = mid + 1; 347 else 348 return (c - cp437table[mid].unicode_base + 349 cp437table[mid].cp437_base); 350 } 351 352 return ('?'); 353 } 354 355 static void 356 vidc_text_printchar(const teken_pos_t *p) 357 { 358 int i; 359 uint8_t attr; 360 struct text_pixel *px; 361 teken_color_t fg, bg, tmp; 362 struct cgatext { 363 uint8_t ch; 364 uint8_t attr; 365 } *addr; 366 367 px = buffer + p->tp_col + p->tp_row * tp.tp_col; 368 fg = teken_256to16(px->a.ta_fgcolor); 369 bg = teken_256to16(px->a.ta_bgcolor); 370 if (px->a.ta_format & TF_BOLD) 371 fg |= TC_LIGHT; 372 if (px->a.ta_format & TF_BLINK) 373 bg |= TC_LIGHT; 374 375 if (px->a.ta_format & TF_REVERSE) { 376 tmp = fg; 377 fg = bg; 378 bg = tmp; 379 } 380 381 attr = (cons_to_vga_colors[bg & 0xf] << 4) | 382 cons_to_vga_colors[fg & 0xf]; 383 addr = (struct cgatext *)vgatext + p->tp_col + p->tp_row * tp.tp_col; 384 addr->ch = vga_get_cp437(px->c); 385 addr->attr = attr; 386 } 387 388 static void 389 vidc_text_putchar(void *s __unused, const teken_pos_t *p, teken_char_t c, 390 const teken_attr_t *a) 391 { 392 int attr, idx; 393 394 idx = p->tp_col + p->tp_row * tp.tp_col; 395 buffer[idx].c = c; 396 buffer[idx].a = *a; 397 vidc_text_printchar(p); 398 } 399 400 static void 401 vidc_text_fill(void *s, const teken_rect_t *r, teken_char_t c, 402 const teken_attr_t *a) 403 { 404 teken_pos_t p; 405 teken_unit_t row, col; 406 407 vidc_text_get_cursor(&row, &col); 408 vidc_text_set_cursor(row, col, false); 409 for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; 410 p.tp_row++) 411 for (p.tp_col = r->tr_begin.tp_col; 412 p.tp_col < r->tr_end.tp_col; p.tp_col++) 413 vidc_text_putchar(s, &p, c, a); 414 vidc_text_set_cursor(row, col, true); 415 } 416 417 static bool 418 vidc_same_pixel(struct text_pixel *px1, struct text_pixel *px2) 419 { 420 if (px1->c != px2->c) 421 return (false); 422 423 if (px1->a.ta_format != px2->a.ta_format) 424 return (false); 425 if (px1->a.ta_fgcolor != px2->a.ta_fgcolor) 426 return (false); 427 if (px1->a.ta_bgcolor != px2->a.ta_bgcolor) 428 return (false); 429 430 return (true); 431 } 432 433 static void 434 vidc_text_copy(void *ptr __unused, const teken_rect_t *r, const teken_pos_t *p) 435 { 436 int srow, drow; 437 int nrow, ncol, x, y; /* Has to be signed - >= 0 comparison */ 438 teken_pos_t d, s; 439 teken_unit_t row, col; 440 441 /* 442 * Copying is a little tricky. We must make sure we do it in 443 * correct order, to make sure we don't overwrite our own data. 444 */ 445 446 nrow = r->tr_end.tp_row - r->tr_begin.tp_row; 447 ncol = r->tr_end.tp_col - r->tr_begin.tp_col; 448 449 vidc_text_get_cursor(&row, &col); 450 vidc_text_set_cursor(row, col, false); 451 if (p->tp_row < r->tr_begin.tp_row) { 452 /* Copy from bottom to top. */ 453 for (y = 0; y < nrow; y++) { 454 d.tp_row = p->tp_row + y; 455 s.tp_row = r->tr_begin.tp_row + y; 456 drow = d.tp_row * tp.tp_col; 457 srow = s.tp_row * tp.tp_col; 458 for (x = 0; x < ncol; x++) { 459 d.tp_col = p->tp_col + x; 460 s.tp_col = r->tr_begin.tp_col + x; 461 462 if (!vidc_same_pixel( 463 &buffer[d.tp_col + drow], 464 &buffer[s.tp_col + srow])) { 465 buffer[d.tp_col + drow] = 466 buffer[s.tp_col + srow]; 467 vidc_text_printchar(&d); 468 } 469 } 470 } 471 } else { 472 /* Copy from top to bottom. */ 473 if (p->tp_col < r->tr_begin.tp_col) { 474 /* Copy from right to left. */ 475 for (y = nrow - 1; y >= 0; y--) { 476 d.tp_row = p->tp_row + y; 477 s.tp_row = r->tr_begin.tp_row + y; 478 drow = d.tp_row * tp.tp_col; 479 srow = s.tp_row * tp.tp_col; 480 for (x = 0; x < ncol; x++) { 481 d.tp_col = p->tp_col + x; 482 s.tp_col = r->tr_begin.tp_col + x; 483 484 if (!vidc_same_pixel( 485 &buffer[d.tp_col + drow], 486 &buffer[s.tp_col + srow])) { 487 buffer[d.tp_col + drow] = 488 buffer[s.tp_col + srow]; 489 vidc_text_printchar(&d); 490 } 491 } 492 } 493 } else { 494 /* Copy from left to right. */ 495 for (y = nrow - 1; y >= 0; y--) { 496 d.tp_row = p->tp_row + y; 497 s.tp_row = r->tr_begin.tp_row + y; 498 drow = d.tp_row * tp.tp_col; 499 srow = s.tp_row * tp.tp_col; 500 for (x = ncol - 1; x >= 0; x--) { 501 d.tp_col = p->tp_col + x; 502 s.tp_col = r->tr_begin.tp_col + x; 503 504 if (!vidc_same_pixel( 505 &buffer[d.tp_col + drow], 506 &buffer[s.tp_col + srow])) { 507 buffer[d.tp_col + drow] = 508 buffer[s.tp_col + srow]; 509 vidc_text_printchar(&d); 510 } 511 } 512 } 513 } 514 } 515 vidc_text_set_cursor(row, col, true); 516 } 517 518 static void 519 vidc_text_param(void *s __unused, int cmd, unsigned int value) 520 { 521 teken_unit_t row, col; 522 523 switch (cmd) { 524 case TP_SETLOCALCURSOR: 525 /* 526 * 0 means normal (usually block), 1 means hidden, and 527 * 2 means blinking (always block) for compatibility with 528 * syscons. We don't support any changes except hiding, 529 * so must map 2 to 0. 530 */ 531 value = (value == 1) ? 0 : 1; 532 /* FALLTHROUGH */ 533 case TP_SHOWCURSOR: 534 vidc_text_get_cursor(&row, &col); 535 if (value == 1) 536 vidc_text_set_cursor(row, col, true); 537 else 538 vidc_text_set_cursor(row, col, false); 539 break; 540 default: 541 /* Not yet implemented */ 542 break; 543 } 544 } 545 546 /* 547 * Not implemented. 548 */ 549 static void 550 vidc_cons_respond(void *s __unused, const void *buf __unused, 551 size_t len __unused) 552 { 553 } 554 555 static void 556 vidc_probe(struct console *cp) 557 { 558 559 /* look for a keyboard */ 560 #if KEYBOARD_PROBE 561 if (probe_keyboard()) 562 #endif 563 { 564 565 cp->c_flags |= C_PRESENTIN; 566 } 567 568 /* XXX for now, always assume we can do BIOS screen output */ 569 cp->c_flags |= C_PRESENTOUT; 570 } 571 572 static bool 573 color_name_to_teken(const char *name, int *val) 574 { 575 if (strcasecmp(name, "black") == 0) { 576 *val = TC_BLACK; 577 return (true); 578 } 579 if (strcasecmp(name, "red") == 0) { 580 *val = TC_RED; 581 return (true); 582 } 583 if (strcasecmp(name, "green") == 0) { 584 *val = TC_GREEN; 585 return (true); 586 } 587 if (strcasecmp(name, "brown") == 0) { 588 *val = TC_BROWN; 589 return (true); 590 } 591 if (strcasecmp(name, "blue") == 0) { 592 *val = TC_BLUE; 593 return (true); 594 } 595 if (strcasecmp(name, "magenta") == 0) { 596 *val = TC_MAGENTA; 597 return (true); 598 } 599 if (strcasecmp(name, "cyan") == 0) { 600 *val = TC_CYAN; 601 return (true); 602 } 603 if (strcasecmp(name, "white") == 0) { 604 *val = TC_WHITE; 605 return (true); 606 } 607 return (false); 608 } 609 610 static int 611 vidc_set_colors(struct env_var *ev, int flags, const void *value) 612 { 613 int val = 0; 614 char buf[2]; 615 const void *evalue; 616 const teken_attr_t *ap; 617 teken_attr_t a; 618 619 if (value == NULL) 620 return (CMD_OK); 621 622 if (color_name_to_teken(value, &val)) { 623 snprintf(buf, sizeof (buf), "%d", val); 624 evalue = buf; 625 } else { 626 char *end; 627 628 errno = 0; 629 val = (int)strtol(value, &end, 0); 630 if (errno != 0 || *end != '\0') { 631 printf("Allowed values are either ansi color name or " 632 "number from range [0-7].\n"); 633 return (CMD_OK); 634 } 635 evalue = value; 636 } 637 638 ap = teken_get_defattr(&teken); 639 a = *ap; 640 if (strcmp(ev->ev_name, "teken.fg_color") == 0) { 641 /* is it already set? */ 642 if (ap->ta_fgcolor == val) 643 return (CMD_OK); 644 a.ta_fgcolor = val; 645 } 646 if (strcmp(ev->ev_name, "teken.bg_color") == 0) { 647 /* is it already set? */ 648 if (ap->ta_bgcolor == val) 649 return (CMD_OK); 650 a.ta_bgcolor = val; 651 } 652 653 /* Improve visibility */ 654 if (a.ta_bgcolor == TC_WHITE) 655 a.ta_bgcolor |= TC_LIGHT; 656 657 env_setenv(ev->ev_name, flags | EV_NOHOOK, evalue, NULL, NULL); 658 teken_set_defattr(&teken, &a); 659 return (CMD_OK); 660 } 661 662 static int 663 vidc_init(int arg) 664 { 665 const teken_attr_t *a; 666 int val; 667 char env[8]; 668 669 if (vidc_started && arg == 0) 670 return (0); 671 672 vidc_started = 1; 673 674 /* 675 * Check Miscellaneous Output Register (Read at 3CCh, Write at 3C2h) 676 * for bit 1 (Input/Output Address Select), which means 677 * color/graphics adapter. 678 */ 679 if (vga_get_reg(VGA_REG_BASE, VGA_GEN_MISC_OUTPUT_R) & VGA_GEN_MO_IOA) 680 vgatext = (uint16_t *)PTOV(VGA_TXT_BASE); 681 else 682 vgatext = (uint16_t *)PTOV(VGA_MEM_BASE + VGA_MEM_SIZE); 683 684 /* set 16bit colors */ 685 val = vga_get_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL); 686 val &= ~VGA_AC_MC_BI; 687 val &= ~VGA_AC_MC_ELG; 688 vga_set_atr(VGA_REG_BASE, VGA_AC_MODE_CONTROL, val); 689 690 tp.tp_row = TEXT_ROWS; 691 tp.tp_col = TEXT_COLS; 692 buffer = malloc(tp.tp_row * tp.tp_col * sizeof(*buffer)); 693 if (buffer == NULL) 694 return (1); 695 696 snprintf(env, sizeof (env), "%u", tp.tp_row); 697 setenv("LINES", env, 1); 698 snprintf(env, sizeof (env), "%u", tp.tp_col); 699 setenv("COLUMNS", env, 1); 700 701 teken_init(&teken, &tf, NULL); 702 teken_set_winsize(&teken, &tp); 703 a = teken_get_defattr(&teken); 704 705 snprintf(env, sizeof(env), "%d", a->ta_fgcolor); 706 env_setenv("teken.fg_color", EV_VOLATILE, env, vidc_set_colors, 707 env_nounset); 708 snprintf(env, sizeof(env), "%d", a->ta_bgcolor); 709 env_setenv("teken.bg_color", EV_VOLATILE, env, vidc_set_colors, 710 env_nounset); 711 712 /* Erase display, this will also fill our screen buffer. */ 713 teken_input(&teken, "\e[J", 3); 714 715 for (int i = 0; i < 10 && vidc_ischar(); i++) 716 (void) vidc_getchar(); 717 718 return (0); /* XXX reinit? */ 719 } 720 721 void 722 vidc_biosputchar(int c) 723 { 724 725 v86.ctl = 0; 726 v86.addr = 0x10; 727 v86.eax = 0xe00 | (c & 0xff); 728 v86.ebx = 0x7; 729 v86int(); 730 } 731 732 static void 733 vidc_putchar(int c) 734 { 735 unsigned char ch = c; 736 737 if (buffer != NULL) 738 teken_input(&teken, &ch, sizeof (ch)); 739 else 740 vidc_biosputchar(c); 741 } 742 743 static int 744 vidc_getchar(void) 745 { 746 int i, c; 747 748 for (i = 0; i < KEYBUFSZ; i++) { 749 if (keybuf[i] != 0) { 750 c = keybuf[i]; 751 keybuf[i] = 0; 752 return (c); 753 } 754 } 755 756 if (vidc_ischar()) { 757 v86.ctl = 0; 758 v86.addr = 0x16; 759 v86.eax = 0x0; 760 v86int(); 761 if ((v86.eax & 0xff) != 0) { 762 return (v86.eax & 0xff); 763 } 764 765 /* extended keys */ 766 switch (v86.eax & 0xff00) { 767 case 0x4800: /* up */ 768 keybuf[0] = '['; 769 keybuf[1] = 'A'; 770 return (0x1b); /* esc */ 771 case 0x4b00: /* left */ 772 keybuf[0] = '['; 773 keybuf[1] = 'D'; 774 return (0x1b); /* esc */ 775 case 0x4d00: /* right */ 776 keybuf[0] = '['; 777 keybuf[1] = 'C'; 778 return (0x1b); /* esc */ 779 case 0x5000: /* down */ 780 keybuf[0] = '['; 781 keybuf[1] = 'B'; 782 return (0x1b); /* esc */ 783 default: 784 return (-1); 785 } 786 } else { 787 return (-1); 788 } 789 } 790 791 static int 792 vidc_ischar(void) 793 { 794 int i; 795 796 for (i = 0; i < KEYBUFSZ; i++) { 797 if (keybuf[i] != 0) { 798 return (1); 799 } 800 } 801 802 v86.ctl = V86_FLAGS; 803 v86.addr = 0x16; 804 v86.eax = 0x100; 805 v86int(); 806 return (!V86_ZR(v86.efl)); 807 } 808 809 #if KEYBOARD_PROBE 810 811 #define PROBE_MAXRETRY 5 812 #define PROBE_MAXWAIT 400 813 #define IO_DUMMY 0x84 814 #define IO_KBD 0x060 /* 8042 Keyboard */ 815 816 /* selected defines from kbdio.h */ 817 #define KBD_STATUS_PORT 4 /* status port, read */ 818 #define KBD_DATA_PORT 0 /* data port, read/write 819 * also used as keyboard command 820 * and mouse command port 821 */ 822 #define KBDC_ECHO 0x00ee 823 #define KBDS_ANY_BUFFER_FULL 0x0001 824 #define KBDS_INPUT_BUFFER_FULL 0x0002 825 #define KBD_ECHO 0x00ee 826 827 /* 7 microsec delay necessary for some keyboard controllers */ 828 static void 829 delay7(void) 830 { 831 /* 832 * I know this is broken, but no timer is available yet at this stage... 833 * See also comments in `delay1ms()'. 834 */ 835 inb(IO_DUMMY); inb(IO_DUMMY); 836 inb(IO_DUMMY); inb(IO_DUMMY); 837 inb(IO_DUMMY); inb(IO_DUMMY); 838 } 839 840 /* 841 * This routine uses an inb to an unused port, the time to execute that 842 * inb is approximately 1.25uS. This value is pretty constant across 843 * all CPU's and all buses, with the exception of some PCI implentations 844 * that do not forward this I/O address to the ISA bus as they know it 845 * is not a valid ISA bus address, those machines execute this inb in 846 * 60 nS :-(. 847 * 848 */ 849 static void 850 delay1ms(void) 851 { 852 int i = 800; 853 while (--i >= 0) 854 (void) inb(0x84); 855 } 856 857 /* 858 * We use the presence/absence of a keyboard to determine whether the internal 859 * console can be used for input. 860 * 861 * Perform a simple test on the keyboard; issue the ECHO command and see 862 * if the right answer is returned. We don't do anything as drastic as 863 * full keyboard reset; it will be too troublesome and take too much time. 864 */ 865 static int 866 probe_keyboard(void) 867 { 868 int retry = PROBE_MAXRETRY; 869 int wait; 870 int i; 871 872 while (--retry >= 0) { 873 /* flush any noise */ 874 while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { 875 delay7(); 876 inb(IO_KBD + KBD_DATA_PORT); 877 delay1ms(); 878 } 879 880 /* wait until the controller can accept a command */ 881 for (wait = PROBE_MAXWAIT; wait > 0; --wait) { 882 if (((i = inb(IO_KBD + KBD_STATUS_PORT)) 883 & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) 884 == 0) 885 break; 886 if (i & KBDS_ANY_BUFFER_FULL) { 887 delay7(); 888 inb(IO_KBD + KBD_DATA_PORT); 889 } 890 delay1ms(); 891 } 892 if (wait <= 0) 893 continue; 894 895 /* send the ECHO command */ 896 outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO); 897 898 /* wait for a response */ 899 for (wait = PROBE_MAXWAIT; wait > 0; --wait) { 900 if (inb(IO_KBD + KBD_STATUS_PORT) & 901 KBDS_ANY_BUFFER_FULL) 902 break; 903 delay1ms(); 904 } 905 if (wait <= 0) 906 continue; 907 908 delay7(); 909 i = inb(IO_KBD + KBD_DATA_PORT); 910 #ifdef PROBE_KBD_BEBUG 911 printf("probe_keyboard: got 0x%x.\n", i); 912 #endif 913 if (i == KBD_ECHO) { 914 /* got the right answer */ 915 return (1); 916 } 917 } 918 919 return (0); 920 } 921 #endif /* KEYBOARD_PROBE */ 922