1 #ident "$Id: ansicon_write.c,v 1.9 2005/01/05 07:45:23 hpa Exp $"
2 /* ----------------------------------------------------------------------- *
4 * Copyright 2004 H. Peter Anvin - All Rights Reserved
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
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 * ----------------------------------------------------------------------- */
32 * Write to the screen using ANSI control codes (about as capable as
40 #include <klibc/compiler.h>
45 } __attribute__((packed));
46 #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
47 #define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
48 #define BIOS_COLS (*(uint16_t *)0x44A)
49 #define BIOS_PAGE (*(uint8_t *)0x462)
52 st_init, /* Normal (no ESC seen) */
53 st_esc, /* ESC seen */
54 st_csi, /* CSI seen */
61 int attr; /* Current display attribute */
62 int vtgraphics; /* VT graphics on/off */
70 struct curxy saved_xy;
72 enum ansi_state state;
73 int pvt; /* Private code? */
74 int nparms; /* Number of parameters seen */
78 static const struct term_state default_state =
81 .attr = 0x07, /* Grey on black */
91 .cursor_type = 0x0607,
97 static struct term_state st;
99 /* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
100 static const char decvt_to_cp437[] =
101 { 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
102 0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 };
105 static void __constructor ansicon_init(void)
107 static com32sys_t ireg; /* Auto-initalized to all zero */
111 memcpy(&st, &default_state, sizeof st);
113 /* Are we disabled? */
114 ireg.eax.w[0] = 0x000b;
115 __intcall(0x22, &ireg, &oreg);
117 if ( (signed char)oreg.ebx.b[1] < 0 ) {
122 /* Force text mode */
123 ireg.eax.w[0] = 0x0005;
124 __intcall(0x22, &ireg, NULL);
126 /* Get cursor shape */
127 ireg.eax.b[1] = 0x03;
128 ireg.ebx.b[1] = BIOS_PAGE;
129 __intcall(0x10, &ireg, &oreg);
130 st.cursor_type = oreg.ecx.w[0];
133 /* Erase a region of the screen */
134 static void ansicon_erase(int x0, int y0, int x1, int y1)
136 static com32sys_t ireg;
138 ireg.eax.w[0] = 0x0600; /* Clear window */
139 ireg.ebx.b[1] = st.attr; /* Fill with current attribute */
144 __intcall(0x10, &ireg, NULL);
147 /* Show or hide the cursor */
148 static void showcursor(int yes)
150 static com32sys_t ireg;
152 ireg.eax.b[1] = 0x01;
153 ireg.ecx.w[0] = yes ? st.cursor_type : 0x2020;
154 __intcall(0x10, &ireg, NULL);
157 static void ansicon_putchar(int ch)
159 static com32sys_t ireg;
160 const int rows = BIOS_ROWS ? BIOS_ROWS+1 : 25;
161 const int cols = BIOS_COLS;
162 const int page = BIOS_PAGE;
163 struct curxy xy = BIOS_CURXY[page];
165 switch ( st.state ) {
169 if ( xy.x > 0 ) xy.x--;
173 int nsp = 8 - (xy.x & 7);
175 ansicon_putchar(' ');
177 return; /* Cursor already updated */
201 /* Print character */
203 if ( st.vtgraphics && (ch & 0xe0) == 0x60 )
204 ch = decvt_to_cp437[ch - 0x60];
206 ireg.eax.b[1] = 0x09;
208 ireg.ebx.b[1] = page;
209 ireg.ebx.b[0] = st.attr;
211 __intcall(0x10, &ireg, NULL);
224 /* Ignore this plus the subsequent character, allows
225 compatibility with Linux sequence to set charset */
229 st.nparms = st.pvt = 0;
230 memset(st.parms, 0, sizeof st.parms);
234 memcpy(&st, &default_state, sizeof st);
235 ansicon_erase(0, 0, cols-1, rows-1);
239 /* Ignore sequence */
247 int p0 = st.parms[0] ? st.parms[0] : 1;
249 if ( ch >= '0' && ch <= '9' ) {
250 st.parms[st.nparms] = st.parms[st.nparms]*10 + (ch-'0');
251 } else if ( ch == ';' ) {
253 if ( st.nparms >= MAX_PARMS )
254 st.nparms = MAX_PARMS-1;
256 } else if ( ch == '?' ) {
263 xy.y = (y < 0) ? 0 : y;
269 xy.y = (y >= rows) ? rows-1 : y;
275 xy.x = (x >= cols) ? cols-1 : x;
281 xy.x = (x < 0) ? 0 : x;
287 xy.y = (y >= rows) ? rows-1 : y;
294 xy.y = (y < 0) ? 0 : y;
301 int x = st.parms[0] - 1;
302 xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
308 int y = st.parms[0] - 1;
309 int x = st.parms[1] - 1;
311 xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
312 xy.y = (y >= rows) ? rows-1 : (y < 0) ? 0 : y;
317 switch ( st.parms[0] ) {
319 ansicon_erase(xy.x, xy.y, cols-1, xy.y);
321 ansicon_erase(0, xy.y+1, cols-1, rows-1);
326 ansicon_erase(0, 0, cols-1, xy.y-1);
328 ansicon_erase(0, xy.y, xy.x-1, xy.y);
332 ansicon_erase(0, 0, cols-1, rows-1);
343 switch ( st.parms[0] ) {
345 ansicon_erase(xy.x, xy.y, cols-1, xy.y);
350 ansicon_erase(0, xy.y, xy.x-1, xy.y);
354 ansicon_erase(0, xy.y, cols-1, xy.y);
366 int set = (ch == 'h');
367 switch ( st.parms[0] ) {
382 static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
385 for ( i = 0 ; i <= st.nparms ; i++ ) {
425 st.fg = ansi2pc[a-30];
436 st.bg = ansi2pc[a-40];
447 /* Turn into an attribute code */
454 else if ( st.intensity == 0 )
468 if ( st.intensity == 2 )
471 st.attr = (bg << 4) | fg;
481 default: /* Includes CAN and SUB */
482 break; /* Drop unknown sequence */
490 /* If we fell off the end of the screen, adjust */
491 if ( xy.x >= cols ) {
495 while ( xy.y >= rows ) {
497 ireg.eax.w[0] = 0x0601;
498 ireg.ebx.b[1] = st.attr;
500 ireg.edx.b[1] = rows-1;
501 ireg.edx.b[0] = cols-1;
502 __intcall(0x10, &ireg, NULL); /* Scroll */
505 /* Update cursor position */
506 ireg.eax.b[1] = 0x02;
507 ireg.ebx.b[1] = page;
508 ireg.edx.b[1] = xy.y;
509 ireg.edx.b[0] = xy.x;
510 __intcall(0x10, &ireg, NULL);
514 ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
516 const unsigned char *bufp = buf;
522 return n; /* Nothing to do */
525 ansicon_putchar(*bufp++);
532 const struct output_dev dev_ansicon_w = {
533 .dev_magic = __DEV_MAGIC,
534 .flags = __DEV_TTY | __DEV_OUTPUT,
535 .fileflags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
536 .write = __ansicon_write,