Adjust memory layout for 2.6.22+ kernels with 32KB setup code
[mknbi.git] / ansiesc.c
1 #include "stddef.h"
2 #include "string.h"
3 #include "etherboot.h"
4 #include "ansiesc.h"
5
6 /*
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2, or (at
10  * your option) any later version.
11  */
12
13 /*
14  *      Display attributes
15  *
16  *      Code          Effect
17  *      <esc>[0m      normal text
18  *      <esc>[1m      high-intensity on
19  *      <esc>[21m     high-intensity off
20  *      <esc>[5m      blinking on
21  *      <esc>[25m     blinking off
22  *      <esc>[7m      reverse video on
23  *      <esc>[27m     reverse video off
24  *      <esc>[3xm     set foreground color:
25  *      <esc>[4xm     set background color. x can be:
26  *                         0 - black                   4 - blue
27  *                         1 - red                     5 - magenta
28  *                         2 - green                   6 - cyan
29  *                         3 - yellow                  7 - white
30  *      <esc>[=xh     set video mode
31  *                         0 - 40x25 mono     (text)  13 - 40x25 16colors (gfx)
32  *                         1 - 40x25 16colors (text)  14 - 80x25 16colors (gfx)
33  *                         2 - 80x25 mono     (text)  15 - 80x25 mono     (gfx)
34  *                         3 - 80x25 16colors (text)  16 - 80x25 16colors (gfx)
35  *                         4 - 40x25 4colors  (gfx)   17 - 80x30 mono     (gfx)
36  *                         5 - 40x25 mono     (gfx)   18 - 80x30 16colors (gfx)
37  *                         6 - 80x25 mono     (gfx)   19 - 40x25 256colors(gfx)
38  *
39  *
40  *      Cursor control
41  *
42  *      Code          Effect
43  *      <esc>[r;cH    move cursor to row r col c (r and c are both numbers)
44  *      <esc>[r;cf    move cursor to row r col c (r and c are both numbers)
45  *      <esc>[rA      move cursor up r rows
46  *      <esc>[rB      move cursor down r rows
47  *      <esc>[cC      move cursor right c columns
48  *      <esc>[cD      move cursor left c columns
49  *      <esc>[?7l     turn off line wrap
50  *      <esc>[?7h     turn on line wrap
51  *      <esc>[J       clear screen and home cursor
52  *      <esc>[K       clear to end of line
53  *      <esc>[s       save the cursor position
54  *      <esc>[u       return cursor to saved position
55  *
56  *      Extended features
57  *
58  *      Code          Effect
59  *      <esc>[a;b;c;d+<data>
60  *                    draw pixel data; use one byte per pixel. Parameters
61  *                    differ depending on the number of parameters passed:
62  *                    cnt
63  *                      "cnt" bytes follow; they will be drawn to the
64  *                      right of the last graphics position
65  *                    rle;col
66  *                      the next "rle" pixels have the value "col"; they
67  *                      will be drawn to the right of the last graphics
68  *                      position
69  *                    x;y;cnt
70  *                      "cnt" bytes follow; they will be drawn relative to
71  *                      the text cursor position with an offset of (x/y)
72  *                    x;y;rle;col
73  *                      the next "rle" pixels have the value "col"; the
74  *                      will be drawn relative to the text cursor position
75  *                      with an offset of (x/y)
76  *      <esc>[a;b;c;d-<data>
77  *                      same as above, but pack pixels into three bits.
78  *
79  */
80
81 #define MAXARGS         8
82 #define MAXSTRARGS      1
83 #define MAXSTRARGLEN    40
84
85 extern union {
86   struct {
87     unsigned char al,ah,bl,bh,cl,ch,dl,dh;
88   } __attribute__ ((packed)) lh;
89   struct {
90     unsigned short ax,bx,cx,dx;
91   } __attribute__ ((packed)) x;
92   unsigned long axbx;
93 } __attribute__ ((packed)) int10ret;
94
95 union axbxstruct {
96   struct {
97     unsigned char al,ah,bl,bh;
98   } __attribute__ ((packed)) lh;
99   struct {
100     unsigned short ax,bx;
101   } __attribute__ ((packed)) x;
102   unsigned long axbx;
103 } __attribute__ ((packed));
104
105 #define int10(a,b,c,d) _int10((unsigned long)(a)+((unsigned long)(b)<<16), \
106                               (unsigned long)(c)+((unsigned long)(d)<<16))
107 extern unsigned long _int10(unsigned long axbx,unsigned long cxdx);
108
109 static enum { esc_init, esc_std, esc_esc, esc_bracket, esc_digit,
110               esc_semicolon, esc_str, esc_quote
111 } esc_state = esc_init;
112
113 /* Don't declare these static, so we can access them from code in other files */
114 unsigned short rows,columns,attr = 7;
115
116 static unsigned short scr,cx = 0,cy = 0, scx = 0,scy = 0;
117 static int fg = 7, bg = 0, blink = 0,reverse = 0, bright = 0;
118 static int wraparound = 1;
119 static int argn = 0;
120 static int argi[MAXARGS];
121 static char args[MAXSTRARGS][MAXSTRARGLEN];
122 static const unsigned char coltable[9] = "\000\004\002\006\001\005\003\007";
123 #ifdef  GFX
124 static unsigned short gfx_rows,gfx_columns,char_width,char_height,gfx_x,gfx_y;
125 static int in_gfx = 0, gfx_packed,gfx_data,gfx_nbits;
126 static int defaultmode = -1, curmode = -1, curmodetype = 0;
127 #endif
128
129 void ansi_reset(void)
130 {
131 #ifdef  GFX
132   /* this will not execute, when the serial console is used, because
133      both curmode and defaultmode will be -1 */
134   if (curmode != defaultmode) {
135     in_gfx = 0;
136     curmodetype = 0;
137     int10(curmode = defaultmode,0,0,0);
138     esc_state = esc_init;
139     ansi_putc('\010'); /* force reinitialization */ }
140   return;
141 #endif
142 }
143
144 void enable_cursor(int enable)
145 {
146 #ifdef  GFX
147   /* this will not execute, when the serial console is used, because
148      curmodetype will be 0 */
149   if (curmodetype == 'G' || curmodetype == 'H') {
150     if (enable)
151       int10(0x09DB,7,1,0);
152     else
153       int10(0x0920,(attr/16)&7,1,0); }
154   return;
155 #endif
156 }
157
158 static void docommand(unsigned char ch)
159 {
160 #ifdef  GFX
161   if (ch == '+' || ch == '-') { /* gfx bitmap */
162     int i;
163     gfx_packed = ((ch == '-') ? 3 : 8);
164     gfx_nbits  = 0;
165     if (argn > 2) {
166       gfx_x    = argi[0];
167       gfx_y    = argi[1];
168       if (curmodetype == 'T') {
169         gfx_x += cx;
170         gfx_y += cy; }
171       else {
172         gfx_x += cx*char_width;
173         gfx_y += cy*char_height; }
174       i        = 2; }
175     else
176       i        = 0;
177     in_gfx   = argi[i+0];
178     if (argn == i+2)
179       while (in_gfx)
180         ansi_putc(argi[i+1]); }
181   else
182 #endif
183   if (ch == 'm') { /* set attribute */
184     int i,j;
185     for (j = 0; (i = argi[j]), (j++ < argn); )
186       if (i == 0 ||       /* reset attributes */
187           i == 20) {
188         blink = reverse = bright = bg = 0; fg = 7;
189         goto doattr; }
190       else if (i == 1) {  /* high intensity on */
191         bright = 1;
192         goto doattr; }
193       else if (i == 21) { /* high intensity off */
194         bright = 0;
195         goto doattr; }
196       else if (i == 5) {  /* blinking on */
197         blink = 1;
198         goto doattr; }
199       else if (i == 25) { /* blinking off */
200         blink = 0;
201         goto doattr; }
202       else if (i == 7) {  /* reverse video on */
203         reverse = 1;
204       isreverse:
205         attr =
206 #ifdef  GFX
207           curmodetype != 'T' ? (fg?128:0)+16*fg+(fg^(8*bright+bg)) :
208 #endif
209           128*blink+16*fg+8*bright+bg; }
210       else if (i == 27) { /* reverse video off */
211         reverse = 0;
212       isnormal:
213         attr =
214 #ifdef  GFX
215           curmodetype != 'T' ? (bg?128:0)+16*bg+(bg^(8*bright+fg)) :
216 #endif
217           128*blink+16*bg+8*bright+fg; }
218       else if (i >= 30 && i <= 37) {
219         fg = coltable[i-30];
220       doattr:
221         if (reverse) goto isreverse; else goto isnormal; }
222       else if (i >= 40 && i <= 47) {
223         bg = coltable[i-40];
224         goto doattr; } }
225   else if (ch == 'H' || /* set cursor position */
226            ch == 'f') { /* set cursor position */
227     cy = argi[0];
228     cx = argi[1];
229     updatecursor:
230     int10(0x0200,256*scr,0,256*cy+cx); }
231   else if (ch == 'A') { /* move cursor up */
232     if (cy < argi[0]) cy = 0;
233     else              cy -= argi[0];
234     goto updatecursor; }
235   else if (ch == 'B') { /* move cursor down */
236     if ((cy += argi[0]) >= rows) cy = rows-1;
237     goto updatecursor; }
238   else if (ch == 'C') { /* move cursor right */
239     if ((cx += argi[0]) >= columns) cx = columns-1;
240     goto updatecursor; }
241   else if (ch == 'D') { /* move cursor left */
242     if (cx < argi[0]) cx = 0;
243     else              cx -= argi[0];
244     goto updatecursor; }
245   else if (ch == 'l') { /* turn off line wrapping or set text mode */
246     if (argi[0] == 7)
247       wraparound = 0;
248 #ifdef  GFX
249     else {  /* text mode */
250       curmodetype = 0;
251       int10(curmode = defaultmode,0,0,0);
252       esc_state = esc_init; }
253 #endif
254   }
255   else if (ch == 'h') { /* turn on line wrapping or set graphics mode */
256     if (argi[0] == 7)
257       wraparound = 1;
258 #ifdef  GFX
259     else {  /* graphics mode */
260       curmodetype = 0;
261       int10(curmode = argi[0],0,0,0);
262       esc_state = esc_init; }
263 #endif
264   }
265   else if (ch == 'J') { /* clear screen and home cursor */
266 #ifdef  GFX
267     int10(0x0600,256*(curmodetype != 'T' ? reverse ? fg : bg : attr),0,
268           256*(rows-1)+columns-1);
269 #else
270     int10(0x0600,256*attr,0,256*(rows-1)+columns-1);
271 #endif
272     cx = cy = 0;
273     goto updatecursor; }
274   else if (ch == 'K')   /* clear to end of line */
275 #ifdef  GFX
276     int10(curmodetype == 'T' ? 0x0920 : 0x09DB,
277           curmodetype == 'T' ? 256*scr+attr : reverse ? fg : bg,
278           columns-cx,0);
279 #else
280     int10(0x0920,256*scr+attr,columns-cx,0);
281 #endif
282   else if (ch == 's') { /* save cursor position */
283     scx = cx; scy = cy; }
284   else if (ch == 'u') { /* restore cursor position */
285     cx = scx; cy = scy;
286     goto updatecursor; }
287   return;
288 }
289
290 void ansi_putc(unsigned int ch)
291 {
292   union axbxstruct u;
293
294 #ifdef  GFX
295   if (in_gfx) {
296     gfx_data   = (gfx_data << 8) | ch;
297     gfx_nbits += 8;
298     while (gfx_nbits >= gfx_packed && in_gfx) {
299       in_gfx--;
300       ch = (gfx_data >> (gfx_nbits -= gfx_packed)) & ((1 << gfx_packed) - 1);
301       if (curmodetype == 'T') {
302         if (gfx_x < columns && gfx_y < rows*2) {
303           int pix[2];
304           int10(0x0200,256*scr,0,        /* move cursor position */
305                 256*(gfx_y/2)+gfx_x++);
306           u.axbx = int10(0x0800,256*scr,0,0);     /* read character/attribute */
307           if (u.lh.al == 0xDB)
308             pix[0] = pix[1] =  u.lh.ah    &0xF;
309           else if (u.lh.al == 0xDC) {
310             pix[0] =          (u.lh.ah/16)&0xF;
311             pix[1] =           u.lh.ah    &0xF; }
312           else
313             pix[0] = pix[1] = (u.lh.ah/16)&0xF;
314           pix[gfx_y&1] = coltable[ch & 0x7];
315           int10(0x0900|                  /* output char */
316                 (pix[0]==pix[1]?0xDB:0xDC),
317                 256*scr+(0x7F&(pix[0]*16+pix[1])),1,0); }
318         if (!in_gfx)
319           int10(0x0200,256*scr,0,        /* restore cursor position */
320                 256*cy+cx); }
321       else if (gfx_x < gfx_columns && gfx_y < gfx_rows)
322         int10(0x0C00|                    /* write pixel */
323               (ch <= 7 ? coltable[ch] : ch),256*scr,gfx_x++,gfx_y); }
324     return; }
325 #endif
326   switch (esc_state) {
327   case esc_esc:
328     if (ch == '[') {
329       esc_state = esc_bracket;
330       argn = 0;
331       memset(&argi, 0, sizeof(argi));
332       memset(args, 0, MAXSTRARGS*MAXSTRARGLEN); }
333     else {
334       esc_state = esc_std;
335       goto doputchar; }
336     break;
337   case esc_bracket:
338   case esc_semicolon:
339     if (ch == '\'') {
340       esc_state = esc_str;
341       break; }
342     /* fall thru */
343     if (ch == '=' || ch == '?')
344       break;
345     /* fall thru */
346   case esc_digit:
347     if (ch >= '0' && ch <= '9') {
348       esc_state = esc_digit;
349       if (argn < MAXARGS)
350         argi[argn] = 10*argi[argn] + ch - '0'; }
351     else
352       quote:
353       if (ch == ';') {
354       esc_state = esc_semicolon;
355       argn++; }
356     else {
357       if (esc_state == esc_digit || esc_state == esc_quote)
358         argn++;
359       esc_state = esc_std;
360       docommand(ch); }
361     break;
362   case esc_str:
363     if (ch == '\'') {
364       esc_state = esc_quote;
365       break; }
366     { int i;
367     if (argn < MAXSTRARGS && (i = strlen(args[argn])) < MAXSTRARGLEN-2)
368       args[argn][i] = ch; }
369     break;
370   case esc_quote:
371     goto quote;
372   case esc_init: {
373     int i;
374     esc_state = esc_std;
375     u.axbx = int10(0x0F00,0,0,0);                 /* get graphics mode information */
376 #ifdef  GFX
377     if (defaultmode < 0)
378       defaultmode = curmode = u.lh.al ? u.lh.al : 3;
379 #endif
380     columns = u.lh.ah;
381     scr     = u.lh.bh;
382     int10(0x0200,256*scr,0,0);           /* put cursor to home position */
383     for (i = 0; ++i < 100; ) {
384       int10(0x0E0A,256*scr,0,0);         /* output LF */
385       int10(0x0300,256*scr,0,0);         /* get cursor position */
386       if (int10ret.lh.dh != i)           /* row */
387         break; }
388     rows    = i;
389     int10(0x0200,256*scr,0,0);           /* put cursor to home position */
390 #ifdef  GFX
391     char_width  = 8;
392     char_height = *(unsigned char *)0x485;
393     if (char_height < 8 || char_height > 20)
394       char_height = 8;
395     gfx_columns = char_width*columns;
396     gfx_rows    = char_height*rows;
397     if (!curmodetype) {
398       int10(0x0941,256*scr+127,1,0);     /* 'A', bright, white on white */
399       u.axbx = int10(0x0800,256*scr,0,0);         /* read character/attribute */
400       if (u.lh.al == 0x41 &&
401           u.lh.ah == 127)
402         curmodetype = 'T';
403       else {
404         int10(0x0C40,256*scr,0,0);       /* write pixel */
405         u.axbx = int10(0x0D00,256*scr,0,0);       /* read pixel color */
406         if (u.lh.al == 0x40)
407           curmodetype = 'H';
408         else
409           curmodetype = 'G'; } }
410 #endif
411     attr = fg = 7;
412     cx = cy = scx = scy = bg = blink = reverse = bright = 0;
413     wraparound = 1;
414 #ifdef  GFX
415     int10(0x0600,                        /* clear screen */
416           curmodetype != 'T' ? 0 : 7*256,0,256*(rows-1)+columns-1); }
417 #else
418     int10(0x0600,                        /* clear screen */
419           7*256,0,256*(rows-1)+columns-1); }
420 #endif
421
422     /* fall thru */
423   default:
424     if (ch == 0x1B)
425       esc_state = esc_esc;
426     else if (ch == '\t') {
427       int i;
428       for (i = 8-cx%8; i--; ) ansi_putc(' '); }
429     else if (ch == '\r') {
430       cx = 0; goto updatecursor; }
431     else if (ch == '\n') {
432       ansi_putc('\r'); goto newline; }
433     else if (ch == '\010') {
434       if (cx) {
435         cx--; goto updatecursor; } }
436     else {
437     doputchar:
438 #ifdef  GFX
439       if (curmodetype == 'G' && (reverse ? fg : bg))
440         int10(0x09DB,(attr/16)&0x07,1,0);/* set background in gfx mode */
441 #endif
442 #ifdef  GFX
443       int10(0x0900|ch,                   /* output char */
444             curmodetype == 'H' ? reverse ? fg*256+bg : bg*256+fg :
445             256*scr+attr,1,0);
446 #else
447       int10(0x0900|ch,256*scr+attr,1,0); /* output char */
448 #endif
449       if (++cx == columns) {
450         if (!wraparound)
451           cx--;
452         else {
453           cx = 0;
454         newline:
455           if (++cy == rows)
456 #ifdef  GFX
457             int10(0x0601,                /* scroll screen */
458                   256*(curmodetype != 'T' ? reverse ? fg : bg : attr),0,
459                   256*--cy+columns-1); }
460 #else
461             int10(0x0601,256*attr,0,     /* scroll screen */
462                   256*--cy+columns-1); }
463 #endif
464       }
465     updatecursor:
466       int10(0x0200,256*scr,0,256*cy+cx); /* update cursor position */ } }
467   return;
468 }