1 /* ----------------------------------------------------------------------- *
3 * Copyright 2004 H. Peter Anvin - All Rights Reserved
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use,
9 * copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following
14 * The above copyright notice and this permission notice shall
15 * be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
26 * ----------------------------------------------------------------------- */
31 * 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 */
55 st_soh
, /* SOH seen */
56 st_sohc
, /* SOH # seen */
57 st_sohc1
, /* SOH # digit seen */
64 int attr
; /* Current display attribute */
65 int vtgraphics
; /* VT graphics on/off */
73 struct curxy saved_xy
;
75 enum ansi_state state
;
76 int pvt
; /* Private code? */
77 int nparms
; /* Number of parameters seen */
81 static const struct term_state default_state
=
84 .attr
= 0x07, /* Grey on black */
94 .cursor_type
= 0x0607,
100 static struct term_state st
;
102 /* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
103 static const char decvt_to_cp437
[] =
104 { 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
105 0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 };
107 /* Reference counter to the screen, to keep track of if we need reinitialization. */
108 static int ansicon_counter
= 0;
111 int __ansicon_open(struct file_info
*fp
)
113 static com32sys_t ireg
; /* Auto-initalized to all zero */
118 if (!ansicon_counter
) {
120 memcpy(&st
, &default_state
, sizeof st
);
122 /* Are we disabled? */
123 ireg
.eax
.w
[0] = 0x000b;
124 __intcall(0x22, &ireg
, &oreg
);
126 if ( (signed char)oreg
.ebx
.b
[1] < 0 ) {
129 /* Force text mode */
130 ireg
.eax
.w
[0] = 0x0005;
131 __intcall(0x22, &ireg
, NULL
);
133 /* Get cursor shape */
134 ireg
.eax
.b
[1] = 0x03;
135 ireg
.ebx
.b
[1] = BIOS_PAGE
;
136 __intcall(0x10, &ireg
, &oreg
);
137 st
.cursor_type
= oreg
.ecx
.w
[0];
145 int __ansicon_close(struct file_info
*fp
)
153 /* Erase a region of the screen */
154 static void ansicon_erase(int x0
, int y0
, int x1
, int y1
)
156 static com32sys_t ireg
;
158 ireg
.eax
.w
[0] = 0x0600; /* Clear window */
159 ireg
.ebx
.b
[1] = st
.attr
; /* Fill with current attribute */
164 __intcall(0x10, &ireg
, NULL
);
167 /* Show or hide the cursor */
168 static void showcursor(int yes
)
170 static com32sys_t ireg
;
172 ireg
.eax
.b
[1] = 0x01;
173 ireg
.ecx
.w
[0] = yes
? st
.cursor_type
: 0x2020;
174 __intcall(0x10, &ireg
, NULL
);
177 static void ansicon_putchar(int ch
)
179 static com32sys_t ireg
;
180 const int rows
= BIOS_ROWS
? BIOS_ROWS
+1 : 25;
181 const int cols
= BIOS_COLS
;
182 const int page
= BIOS_PAGE
;
183 struct curxy xy
= BIOS_CURXY
[page
];
185 switch ( st
.state
) {
192 if ( xy
.x
> 0 ) xy
.x
--;
196 int nsp
= 8 - (xy
.x
& 7);
198 ansicon_putchar(' ');
200 return; /* Cursor already updated */
224 /* Print character */
226 if ( st
.vtgraphics
&& (ch
& 0xe0) == 0x60 )
227 ch
= decvt_to_cp437
[ch
- 0x60];
229 ireg
.eax
.b
[1] = 0x09;
231 ireg
.ebx
.b
[1] = page
;
232 ireg
.ebx
.b
[0] = st
.attr
;
234 __intcall(0x10, &ireg
, NULL
);
247 /* Ignore this plus the subsequent character, allows
248 compatibility with Linux sequence to set charset */
252 st
.nparms
= st
.pvt
= 0;
253 memset(st
.parms
, 0, sizeof st
.parms
);
257 memcpy(&st
, &default_state
, sizeof st
);
258 ansicon_erase(0, 0, cols
-1, rows
-1);
262 /* Ignore sequence */
270 int p0
= st
.parms
[0] ? st
.parms
[0] : 1;
272 if ( ch
>= '0' && ch
<= '9' ) {
273 st
.parms
[st
.nparms
] = st
.parms
[st
.nparms
]*10 + (ch
-'0');
274 } else if ( ch
== ';' ) {
276 if ( st
.nparms
>= MAX_PARMS
)
277 st
.nparms
= MAX_PARMS
-1;
279 } else if ( ch
== '?' ) {
286 xy
.y
= (y
< 0) ? 0 : y
;
292 xy
.y
= (y
>= rows
) ? rows
-1 : y
;
298 xy
.x
= (x
>= cols
) ? cols
-1 : x
;
304 xy
.x
= (x
< 0) ? 0 : x
;
310 xy
.y
= (y
>= rows
) ? rows
-1 : y
;
317 xy
.y
= (y
< 0) ? 0 : y
;
324 int x
= st
.parms
[0] - 1;
325 xy
.x
= (x
>= cols
) ? cols
-1 : (x
< 0) ? 0 : x
;
331 int y
= st
.parms
[0] - 1;
332 int x
= st
.parms
[1] - 1;
334 xy
.x
= (x
>= cols
) ? cols
-1 : (x
< 0) ? 0 : x
;
335 xy
.y
= (y
>= rows
) ? rows
-1 : (y
< 0) ? 0 : y
;
340 switch ( st
.parms
[0] ) {
342 ansicon_erase(xy
.x
, xy
.y
, cols
-1, xy
.y
);
344 ansicon_erase(0, xy
.y
+1, cols
-1, rows
-1);
349 ansicon_erase(0, 0, cols
-1, xy
.y
-1);
351 ansicon_erase(0, xy
.y
, xy
.x
-1, xy
.y
);
355 ansicon_erase(0, 0, cols
-1, rows
-1);
366 switch ( st
.parms
[0] ) {
368 ansicon_erase(xy
.x
, xy
.y
, cols
-1, xy
.y
);
373 ansicon_erase(0, xy
.y
, xy
.x
-1, xy
.y
);
377 ansicon_erase(0, xy
.y
, cols
-1, xy
.y
);
389 int set
= (ch
== 'h');
390 switch ( st
.parms
[0] ) {
405 static const int ansi2pc
[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
408 for ( i
= 0 ; i
<= st
.nparms
; i
++ ) {
448 st
.fg
= ansi2pc
[a
-30];
459 st
.bg
= ansi2pc
[a
-40];
470 /* Turn into an attribute code */
477 else if ( st
.intensity
== 0 )
491 if ( st
.intensity
== 2 )
494 st
.attr
= (bg
<< 4) | fg
;
504 default: /* Includes CAN and SUB */
505 break; /* Drop unknown sequence */
521 int n
= (unsigned char)ch
- '0';
533 int n
= (unsigned char)ch
- '0';
538 /* Emulate the appropriate CSI m sequence */
539 if (st
.parms
[0] < console_color_table_size
) {
541 for (p
= console_color_table
[st
.parms
[0]].ansi
; *p
; p
++)
543 ansicon_putchar('m');
552 /* If we fell off the end of the screen, adjust */
553 if ( xy
.x
>= cols
) {
557 while ( xy
.y
>= rows
) {
559 ireg
.eax
.w
[0] = 0x0601;
560 ireg
.ebx
.b
[1] = st
.attr
;
562 ireg
.edx
.b
[1] = rows
-1;
563 ireg
.edx
.b
[0] = cols
-1;
564 __intcall(0x10, &ireg
, NULL
); /* Scroll */
567 /* Update cursor position */
568 ireg
.eax
.b
[1] = 0x02;
569 ireg
.ebx
.b
[1] = page
;
570 ireg
.edx
.b
[1] = xy
.y
;
571 ireg
.edx
.b
[0] = xy
.x
;
572 __intcall(0x10, &ireg
, NULL
);
576 ssize_t
__ansicon_write(struct file_info
*fp
, const void *buf
, size_t count
)
578 const unsigned char *bufp
= buf
;
584 return n
; /* Nothing to do */
587 ansicon_putchar(*bufp
++);
594 const struct output_dev dev_ansicon_w
= {
595 .dev_magic
= __DEV_MAGIC
,
596 .flags
= __DEV_TTY
| __DEV_OUTPUT
,
597 .fileflags
= O_WRONLY
| O_CREAT
| O_TRUNC
| O_APPEND
,
598 .write
= __ansicon_write
,
599 .close
= __ansicon_close
,
600 .open
= __ansicon_open
,