|
|
1.1 root 1: /*
2: * <console.c>
3: *
4: * Simple text console
5: *
6: * Copyright (C) 2002, 2003 Samuel Rydh ([email protected])
7: * Copyright (C) 2005 Stefan Reinauer <[email protected]>
8: *
9: * This program is free software; you can redistribute it and/or
10: * modify it under the terms of the GNU General Public License
11: * as published by the Free Software Foundation
12: *
13: */
14:
15: #include "config.h"
16: #include "libopenbios/bindings.h"
17: #include "libopenbios/fontdata.h"
18: #include "libopenbios/console.h"
19: #include "packages/video.h"
20:
21: #define FONT_ADJ_HEIGHT (FONT_HEIGHT + 2)
22:
23: // Warning: will hang on purpose when encountering unknown codes
24: //#define DEBUG_CONSOLE
25: #ifdef DEBUG_CONSOLE
26: #define DPRINTF(fmt, args...) \
27: do { \
28: printk(fmt , ##args); \
29: for (;;); \
30: } while (0)
31: #else
32: #define DPRINTF(fmt, args...) do {} while(0)
33: #endif
34:
35: typedef enum {
36: ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
37: EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
38: ESpalette
39: } vc_state_t;
40:
41: #define NPAR 16
42: static struct {
43: int inited;
44: int physw, physh;
45: int w,h;
46:
47: int x,y;
48: char *buf;
49:
50: int cursor_on;
51: vc_state_t vc_state;
52: unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current
53: escape sequence */
54: } cons;
55:
56: static int
57: get_conschar( int x, int y )
58: {
59: if( (unsigned int)x < cons.w && (unsigned int)y < cons.h )
60: return cons.buf[y*cons.w + x];
61: return ' ';
62: }
63:
64: static void
65: draw_char( unsigned int h, unsigned int v )
66: {
67: const unsigned char *c = fontdata;
68: int x, y, xx, rskip, m;
69: int invert = (h==cons.x && v==cons.y && cons.cursor_on);
70: int ch = get_conschar( h, v );
71:
72: while( h >= cons.w || v >= cons.h )
73: return;
74:
75: h *= FONT_WIDTH;
76: v *= FONT_ADJ_HEIGHT;
77:
78: rskip = (FONT_WIDTH > 8)? 2 : 1;
79: c += rskip * (unsigned int)(ch & 0xff) * FONT_HEIGHT;
80:
81: for( x=0; x<FONT_WIDTH; x++ ) {
82: xx = x % 8;
83: if( x && !xx )
84: c++;
85: m = (1<<(7-xx));
86: for( y=0; y<FONT_HEIGHT; y++ ){
87: int col = ((!(c[rskip*y] & m)) != invert) ? 254 : 0;
88: draw_pixel( h+x, v+y+1, col );
89: }
90: draw_pixel( h+x, v, 254 );
91: draw_pixel( h+x, v+FONT_HEIGHT+1, 254 );
92: }
93: }
94:
95: static void
96: show_cursor( int show )
97: {
98: if( cons.cursor_on == show )
99: return;
100: cons.cursor_on = show;
101: draw_char( cons.x, cons.y );
102: }
103:
104:
105: static void
106: draw_line( int n )
107: {
108: int i;
109:
110: if( n >= cons.h || n < 0 )
111: return;
112: for( i=0; i<cons.w; i++ )
113: draw_char( i, n );
114: }
115:
116: #if 0
117: static void
118: refresh( void )
119: {
120: int i;
121: for( i=0; i<cons.h; i++ )
122: draw_line(i);
123: }
124: #endif
125:
126: int
127: console_init( void )
128: {
129: if( video_get_res(&cons.physw,&cons.physh) < 0 )
130: return -1;
131:
132: set_color( 0, 0 );
133:
134: cons.w = cons.physw/FONT_WIDTH;
135: cons.h = cons.physh/FONT_ADJ_HEIGHT;
136: cons.buf = malloc( cons.w * cons.h );
137: cons.inited = 1;
138: cons.x = cons.y = 0;
139: cons.vc_state = ESnormal;
140: return 0;
141: }
142:
143: void
144: console_close( void )
145: {
146: if( !cons.inited )
147: return;
148: free( cons.buf );
149: cons.inited = 0;
150: }
151:
152: static void
153: rec_char( int ch, int x, int y )
154: {
155: if( (unsigned int)x < cons.w && (unsigned int)y < cons.h ) {
156: cons.buf[y*cons.w + x] = ch;
157: draw_char( x, y );
158: }
159: }
160:
161: static void
162: scroll1( void )
163: {
164: int x, y;
165:
166: video_scroll(FONT_ADJ_HEIGHT);
167:
168: for (y = 1; y < cons.h - 1; y++) {
169: for (x = 0; x < cons.w; x++)
170: cons.buf[(y - 1) * cons.w + x] = cons.buf[y * cons.w + x];
171: }
172: for (x = 0; x < cons.w; x++)
173: cons.buf[(cons.h - 1) * cons.w + x] = ' ';
174: draw_line(cons.h - 1);
175: }
176:
177: // Insert char
178: static void csi_at(unsigned int nr)
179: {
180: unsigned int x;
181:
182: if (nr > cons.w - cons.x)
183: nr = cons.w - cons.x;
184: else if (!nr)
185: return;
186:
187: for (x = cons.x + nr; x < cons.w - 1; x++)
188: cons.buf[cons.y * cons.w + x - nr] = cons.buf[cons.y * cons.w + x];
189: for (x = cons.x; x < cons.x + nr; x++)
190: cons.buf[cons.y * cons.w + x] = ' ';
191: draw_line(cons.y);
192: }
193:
194: static void
195: do_con_trol(unsigned char ch)
196: {
197: unsigned int i, j;
198:
199: switch (ch) {
200: case 7:
201: // BEL
202: return;
203: case 8:
204: // BS
205: if (cons.x)
206: cons.x--;
207: return;
208: case 9:
209: // HT
210: cons.x = (cons.x + 8) & ~7;
211: return;
212: case 10:
213: // LF
214: cons.x = 0;
215: cons.y++;
216: return;
217: case 12:
218: // FF
219: for (i = 0; i < cons.h; i++) {
220: for (j = 0; j < cons.w; j++)
221: cons.buf[i * cons.w + j] = ' ';
222: draw_line(i);
223: }
224: cons.x = cons.y = 0;
225: return;
226: case 13:
227: // CR
228: cons.x = 0;
229: return;
230: case 25:
231: // EM
232: return;
233: case 24: // CAN
234: case 26: // SUB
235: cons.vc_state = ESnormal;
236: return;
237: case 27:
238: // ESC
239: cons.vc_state = ESesc;
240: return;
241: }
242: if (ch < 32)
243: DPRINTF("Unhandled control char %d\n", ch);
244:
245: switch (cons.vc_state) {
246: case ESesc:
247: cons.vc_state = ESnormal;
248: switch (ch) {
249: case '[':
250: cons.vc_state = ESsquare;
251: return;
252: case 'M':
253: scroll1();
254: return;
255: default:
256: DPRINTF("Unhandled basic escape code '%c'\n", ch);
257: return;
258: }
259: return;
260: case ESsquare:
261: for(cons.vc_npar = 0; cons.vc_npar < NPAR ; cons.vc_npar++)
262: cons.vc_par[cons.vc_npar] = 0;
263: cons.vc_npar = 0;
264: cons.vc_state = ESgetpars;
265: // Fall through
266: case ESgetpars:
267: if (ch == ';' && cons.vc_npar < NPAR - 1) {
268: cons.vc_npar++;
269: return;
270: } else if (ch >= '0' && ch <= '9') {
271: cons.vc_par[cons.vc_npar] *= 10;
272: cons.vc_par[cons.vc_npar] += ch - '0';
273: return;
274: } else
275: cons.vc_state=ESgotpars;
276: // Fall through
277: case ESgotpars:
278: cons.vc_state = ESnormal;
279: switch(ch) {
280: case 'A':
281: // Cursor up
282: if (cons.vc_par[0] == 0)
283: cons.vc_par[0] = 1;
284: if (cons.y - cons.vc_par[0] > 0)
285: cons.y -= cons.vc_par[0];
286: return;
287: case 'B':
288: // Cursor down
289: if (cons.vc_par[0] == 0)
290: cons.vc_par[0] = 1;
291: if (cons.y + cons.vc_par[0] < cons.h - 1)
292: cons.y += cons.vc_par[0];
293: return;
294: case 'C':
295: // Cursor right
296: if (cons.vc_par[0] == 0)
297: cons.vc_par[0] = 1;
298: if (cons.x + cons.vc_par[0] < cons.w - 1)
299: cons.x += cons.vc_par[0];
300: return;
301: case 'D':
302: // Cursor left
303: if (cons.vc_par[0] == 0)
304: cons.vc_par[0] = 1;
305: if (cons.x - cons.vc_par[0] > 0)
306: cons.x -= cons.vc_par[0];
307: return;
308: case 'H':
309: case 'f':
310: // Set cursor position
311: if (cons.vc_par[0])
312: cons.vc_par[0]--;
313:
314: if (cons.vc_par[1])
315: cons.vc_par[1]--;
316:
317: cons.x = cons.vc_par[1];
318: cons.y = cons.vc_par[0];
319: return;
320: case 'J':
321: if (cons.vc_par[0] == 0 && (unsigned int)cons.y < (unsigned int)cons.h &&
322: (unsigned int)cons.x < (unsigned int)cons.w) {
323: // erase from cursor to end of display
324: for (i = cons.x; i < cons.w; i++)
325: cons.buf[cons.y * cons.w + i] = ' ';
326: draw_line(cons.y);
327: for (j = cons.y + 1; j < cons.h; j++) {
328: for (i = 0; i < cons.w; i++)
329: cons.buf[j * cons.w + i] = ' ';
330: draw_line(j);
331: }
332: } else {
333: DPRINTF("Unhandled CSI J code '%c'\n", cons.vc_par[0]);
334: }
335: return;
336: case 'K':
337: switch (cons.vc_par[0]) {
338: case 0: /* erase from cursor to end of line */
339: for (i = cons.x; i < cons.w; i++)
340: cons.buf[cons.y * cons.w + i] = ' ';
341: draw_line(cons.y);
342: return;
343: case 1: /* erase from start of line to cursor */
344: for (i = 0; i <= cons.x; i++)
345: cons.buf[cons.y * cons.w + i] = ' ';
346: draw_line(cons.y);
347: return;
348: case 2: /* erase whole line */
349: for (i = 0; i < cons.w; i++)
350: cons.buf[cons.y * cons.w + i] = ' ';
351: draw_line(cons.y);
352: return;
353: default:
354: DPRINTF("Unhandled CSI K code '%c'\n", cons.vc_par[0]);
355: return;
356: }
357: return;
358: case 'M':
359: if (cons.vc_par[0] == 1)
360: scroll1();
361: else
362: DPRINTF("Unhandled CSI M %d\n", cons.vc_par[0]);
363: return;
364: case 'm':
365: // Attributes are ignored
366: return;
367: case '@':
368: csi_at(cons.vc_par[0]);
369: return;
370: default:
371: DPRINTF("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n",
372: ch, cons.vc_par[0], cons.vc_par[1], cons.vc_par[2],
373: cons.vc_par[3], cons.vc_par[4]);
374: return;
375: }
376: return;
377: default:
378: cons.vc_state = ESnormal;
379: rec_char(ch, cons.x++, cons.y);
380: return;
381: }
382: }
383:
384: int
385: console_draw_fstr(const char *str, int len)
386: {
387: unsigned int y, x;
388: unsigned char ch;
389:
390: if (!str || len <= 0) {
391: return 0;
392: }
393:
394: if( !cons.inited && console_init() )
395: return -1;
396:
397: show_cursor(0);
398: while((ch = *str++) && len--) {
399: do_con_trol(ch);
400:
401: if( cons.x >= cons.w ) {
402: cons.x=0, cons.y++;
403: }
404: if( cons.y >= cons.h ) {
405: for( y=0; y<cons.h-1; y++ )
406: for( x=0; x<cons.w; x++ )
407: cons.buf[y*cons.w + x] = cons.buf[(y+1)*cons.w + x];
408: cons.y = cons.h-1;
409: cons.x = 0;
410: scroll1();
411: }
412: }
413: show_cursor(1);
414: return 0;
415: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.