1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved 4 * Copyright 2009 Intel Corporation; author: H. Peter Anvin 5 * 6 * Permission is hereby granted, free of charge, to any person 7 * obtaining a copy of this software and associated documentation 8 * files (the "Software"), to deal in the Software without 9 * restriction, including without limitation the rights to use, 10 * copy, modify, merge, publish, distribute, sublicense, and/or 11 * sell copies of the Software, and to permit persons to whom 12 * the Software is furnished to do so, subject to the following 13 * conditions: 14 * 15 * The above copyright notice and this permission notice shall 16 * be included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 * OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * ----------------------------------------------------------------------- */ 28 29 /* 30 * ansicon_write.c 31 * 32 * Write to the screen using ANSI control codes (about as capable as 33 * DOS' ANSI.SYS.) 34 */ 35 36 #include <errno.h> 37 #include <string.h> 38 #include <minmax.h> 39 #include <colortbl.h> 40 #include <klibc/compiler.h> 41 #include <syslinux/config.h> 42 #include "file.h" 43 #include "ansi.h" 44 #include <syslinux/firmware.h> 45 #include "graphics.h" 46 47 static void ansicon_erase(const struct term_state *, int, int, int, int); 48 static void ansicon_write_char(int, int, uint8_t, const struct term_state *); 49 static void ansicon_showcursor(const struct term_state *); 50 static void ansicon_scroll_up(const struct term_state *); 51 static void ansicon_set_cursor(int, int, bool); 52 53 static struct term_state ts; 54 struct ansi_ops __ansicon_ops = { 55 .erase = ansicon_erase, 56 .write_char = ansicon_write_char, 57 .showcursor = ansicon_showcursor, 58 .set_cursor = ansicon_set_cursor, 59 .scroll_up = ansicon_scroll_up, 60 .beep = __ansicon_beep, 61 }; 62 63 static struct term_info ti = { 64 .disabled = 0, 65 .ts = &ts, 66 .op = &__ansicon_ops 67 }; 68 69 #define TEXT_MODE 0x0005 70 71 /* Reference counter to the screen, to keep track of if we need 72 reinitialization. */ 73 static int ansicon_counter = 0; 74 75 /* Common setup */ 76 int __ansicon_open(struct file_info *fp) 77 { 78 if (!ansicon_counter) { 79 /* Are we disabled? */ 80 if (syslinux_serial_console_info()->flowctl & 0x8000) { 81 ti.disabled = 1; 82 ti.rows = 25; 83 ti.cols = 80; 84 } else { 85 /* Force text mode */ 86 firmware->o_ops->text_mode(); 87 88 /* Initial state */ 89 firmware->o_ops->get_mode(&ti.cols, &ti.rows); 90 __ansi_init(&ti); 91 92 /* Get cursor shape and position */ 93 firmware->o_ops->get_cursor(&ti.ts->xy.x, &ti.ts->xy.y); 94 } 95 } 96 97 fp->o.rows = ti.rows; 98 fp->o.cols = ti.cols; 99 100 ansicon_counter++; 101 return 0; 102 } 103 104 int __ansicon_close(struct file_info *fp) 105 { 106 (void)fp; 107 108 ansicon_counter--; 109 return 0; 110 } 111 112 /* Turn ANSI attributes into VGA attributes */ 113 static uint8_t ansicon_attribute(const struct term_state *st) 114 { 115 int bg = st->bg; 116 int fg; 117 118 if (st->underline) 119 fg = 0x01; 120 else if (st->intensity == 0) 121 fg = 0x08; 122 else 123 fg = st->fg; 124 125 if (st->reverse) { 126 bg = fg & 0x07; 127 fg &= 0x08; 128 fg |= st->bg; 129 } 130 131 if (st->blink) 132 bg ^= 0x08; 133 134 if (st->intensity == 2) 135 fg ^= 0x08; 136 137 return (bg << 4) | fg; 138 } 139 140 /* Erase a region of the screen */ 141 static void ansicon_erase(const struct term_state *st, 142 int x0, int y0, int x1, int y1) 143 { 144 uint8_t attribute = ansicon_attribute(st); 145 146 if (firmware->o_ops->erase) 147 firmware->o_ops->erase(x0, y0, x1, y1, attribute); 148 } 149 150 /* Show or hide the cursor */ 151 static void ansicon_showcursor(const struct term_state *st) 152 { 153 firmware->o_ops->showcursor(st); 154 } 155 156 static void ansicon_set_cursor(int x, int y, bool visible) 157 { 158 firmware->o_ops->set_cursor(x, y, visible); 159 } 160 161 static void ansicon_write_char(int x, int y, uint8_t ch, 162 const struct term_state *st) 163 { 164 uint8_t attribute = ansicon_attribute(st); 165 ansicon_set_cursor(x, y, false); 166 167 firmware->o_ops->write_char(ch, attribute); 168 } 169 170 static void ansicon_scroll_up(const struct term_state *st) 171 { 172 uint8_t rows, cols, attribute; 173 174 cols = ti.cols - 1; 175 rows = ti.rows - 1; 176 attribute = ansicon_attribute(st); 177 178 firmware->o_ops->scroll_up(cols, rows, attribute); 179 } 180 181 ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count) 182 { 183 const unsigned char *bufp = buf; 184 size_t n = 0; 185 186 (void)fp; 187 188 if (ti.disabled) 189 return count; /* Nothing to do */ 190 191 while (count--) { 192 __ansi_putchar(&ti, *bufp++); 193 n++; 194 } 195 196 return n; 197 } 198 199 void __ansicon_beep(void) 200 { 201 if (firmware->o_ops->beep) 202 firmware->o_ops->beep(); 203 } 204 205 const struct output_dev dev_ansicon_w = { 206 .dev_magic = __DEV_MAGIC, 207 .flags = __DEV_TTY | __DEV_OUTPUT, 208 .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 209 .write = __ansicon_write, 210 .close = __ansicon_close, 211 .open = __ansicon_open, 212 }; 213