Merging upstream version 5.01+dfsg.
[syslinux-debian/hramrach.git] / com32 / lib / sys / ansicon_write.c
blobe5483fbcd4dd994dca429954096b451727aab4f3
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
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:
15 * The above copyright notice and this permission notice shall
16 * be included in all copies or substantial portions of the Software.
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.
27 * ----------------------------------------------------------------------- */
30 * ansicon_write.c
32 * Write to the screen using ANSI control codes (about as capable as
33 * DOS' ANSI.SYS.)
36 #include <errno.h>
37 #include <string.h>
38 #include <com32.h>
39 #include <minmax.h>
40 #include <colortbl.h>
41 #include <klibc/compiler.h>
42 #include <syslinux/config.h>
43 #include "file.h"
44 #include "ansi.h"
45 #include "graphics.h"
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);
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,
63 static struct term_info ti = {
64 .disabled = 0,
65 .ts = &ts,
66 .op = &__ansicon_ops
69 #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
70 #define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
71 #define BIOS_COLS (*(uint16_t *)0x44A)
72 #define BIOS_PAGE (*(uint8_t *)0x462)
74 /* Reference counter to the screen, to keep track of if we need
75 reinitialization. */
76 static int ansicon_counter = 0;
78 static uint16_t cursor_type; /* Saved cursor pattern */
80 /* Common setup */
81 int __ansicon_open(struct file_info *fp)
83 static com32sys_t ireg; /* Auto-initalized to all zero */
84 com32sys_t oreg;
86 if (!ansicon_counter) {
87 /* Are we disabled? */
88 if (syslinux_serial_console_info()->flowctl & 0x8000) {
89 ti.disabled = 1;
90 ti.rows = 25;
91 ti.cols = 80;
92 } else {
93 /* Force text mode */
94 syslinux_force_text_mode();
96 /* Initial state */
97 ti.rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
98 ti.cols = BIOS_COLS;
99 __ansi_init(&ti);
101 /* Get cursor shape and position */
102 ireg.eax.b[1] = 0x03;
103 ireg.ebx.b[1] = BIOS_PAGE;
104 __intcall(0x10, &ireg, &oreg);
105 cursor_type = oreg.ecx.w[0];
106 ti.ts->xy.x = oreg.edx.b[0];
107 ti.ts->xy.y = oreg.edx.b[1];
111 fp->o.rows = ti.rows;
112 fp->o.cols = ti.cols;
114 ansicon_counter++;
115 return 0;
118 int __ansicon_close(struct file_info *fp)
120 (void)fp;
122 ansicon_counter--;
123 return 0;
126 /* Turn ANSI attributes into VGA attributes */
127 static uint8_t ansicon_attribute(const struct term_state *st)
129 int bg = st->bg;
130 int fg;
132 if (st->underline)
133 fg = 0x01;
134 else if (st->intensity == 0)
135 fg = 0x08;
136 else
137 fg = st->fg;
139 if (st->reverse) {
140 bg = fg & 0x07;
141 fg &= 0x08;
142 fg |= st->bg;
145 if (st->blink)
146 bg ^= 0x08;
148 if (st->intensity == 2)
149 fg ^= 0x08;
151 return (bg << 4) | fg;
154 /* Erase a region of the screen */
155 static void ansicon_erase(const struct term_state *st,
156 int x0, int y0, int x1, int y1)
158 static com32sys_t ireg;
160 ireg.eax.w[0] = 0x0600; /* Clear window */
161 ireg.ebx.b[1] = ansicon_attribute(st);
162 ireg.ecx.b[0] = x0;
163 ireg.ecx.b[1] = y0;
164 ireg.edx.b[0] = x1;
165 ireg.edx.b[1] = y1;
166 __intcall(0x10, &ireg, NULL);
169 /* Show or hide the cursor */
170 static void ansicon_showcursor(const struct term_state *st)
172 static com32sys_t ireg;
174 ireg.eax.b[1] = 0x01;
175 ireg.ecx.w[0] = st->cursor ? cursor_type : 0x2020;
176 __intcall(0x10, &ireg, NULL);
179 static void ansicon_set_cursor(int x, int y, bool visible)
181 const int page = BIOS_PAGE;
182 struct curxy xy = BIOS_CURXY[page];
183 static com32sys_t ireg;
185 (void)visible;
187 if (xy.x != x || xy.y != y) {
188 ireg.eax.b[1] = 0x02;
189 ireg.ebx.b[1] = page;
190 ireg.edx.b[1] = y;
191 ireg.edx.b[0] = x;
192 __intcall(0x10, &ireg, NULL);
196 static void ansicon_write_char(int x, int y, uint8_t ch,
197 const struct term_state *st)
199 static com32sys_t ireg;
201 ansicon_set_cursor(x, y, false);
203 ireg.eax.b[1] = 0x09;
204 ireg.eax.b[0] = ch;
205 ireg.ebx.b[1] = BIOS_PAGE;
206 ireg.ebx.b[0] = ansicon_attribute(st);
207 ireg.ecx.w[0] = 1;
208 __intcall(0x10, &ireg, NULL);
211 static void ansicon_scroll_up(const struct term_state *st)
213 static com32sys_t ireg;
215 ireg.eax.w[0] = 0x0601;
216 ireg.ebx.b[1] = ansicon_attribute(st);
217 ireg.ecx.w[0] = 0;
218 ireg.edx.b[1] = ti.rows - 1;
219 ireg.edx.b[0] = ti.cols - 1;
220 __intcall(0x10, &ireg, NULL); /* Scroll */
223 ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
225 const unsigned char *bufp = buf;
226 size_t n = 0;
228 (void)fp;
230 if (ti.disabled)
231 return count; /* Nothing to do */
233 while (count--) {
234 __ansi_putchar(&ti, *bufp++);
235 n++;
238 return n;
241 void __ansicon_beep(void)
243 static com32sys_t ireg;
245 ireg.eax.w[0] = 0x0e07;
246 ireg.ebx.b[1] = BIOS_PAGE;
247 __intcall(0x10, &ireg, NULL);
250 const struct output_dev dev_ansicon_w = {
251 .dev_magic = __DEV_MAGIC,
252 .flags = __DEV_TTY | __DEV_OUTPUT,
253 .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
254 .write = __ansicon_write,
255 .close = __ansicon_close,
256 .open = __ansicon_open,