1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: #include "qemu-common.h"
25: #include "console.h"
26: #include "qemu-timer.h"
27:
28:
29: #define DEFAULT_BACKSCROLL 512
30: #define MAX_CONSOLES 12
31:
32: #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33: #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
34:
35: typedef struct TextAttributes {
36: uint8_t fgcol:4;
37: uint8_t bgcol:4;
38: uint8_t bold:1;
39: uint8_t uline:1;
40: uint8_t blink:1;
41: uint8_t invers:1;
42: uint8_t unvisible:1;
43: } TextAttributes;
44:
45: typedef struct TextCell {
46: uint8_t ch;
47: TextAttributes t_attrib;
48: } TextCell;
49:
50: #define MAX_ESC_PARAMS 3
51:
52: enum TTYState {
53: TTY_STATE_NORM,
54: TTY_STATE_ESC,
55: TTY_STATE_CSI,
56: };
57:
58: typedef struct QEMUFIFO {
59: uint8_t *buf;
60: int buf_size;
61: int count, wptr, rptr;
62: } QEMUFIFO;
63:
64: static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
65: {
66: int l, len;
67:
68: l = f->buf_size - f->count;
69: if (len1 > l)
70: len1 = l;
71: len = len1;
72: while (len > 0) {
73: l = f->buf_size - f->wptr;
74: if (l > len)
75: l = len;
76: memcpy(f->buf + f->wptr, buf, l);
77: f->wptr += l;
78: if (f->wptr >= f->buf_size)
79: f->wptr = 0;
80: buf += l;
81: len -= l;
82: }
83: f->count += len1;
84: return len1;
85: }
86:
87: static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
88: {
89: int l, len;
90:
91: if (len1 > f->count)
92: len1 = f->count;
93: len = len1;
94: while (len > 0) {
95: l = f->buf_size - f->rptr;
96: if (l > len)
97: l = len;
98: memcpy(buf, f->buf + f->rptr, l);
99: f->rptr += l;
100: if (f->rptr >= f->buf_size)
101: f->rptr = 0;
102: buf += l;
103: len -= l;
104: }
105: f->count -= len1;
106: return len1;
107: }
108:
109: typedef enum {
110: GRAPHIC_CONSOLE,
111: TEXT_CONSOLE,
112: TEXT_CONSOLE_FIXED_SIZE
113: } console_type_t;
114:
115:
116:
117: struct TextConsole {
118: console_type_t console_type;
119: DisplayState *ds;
120:
121: vga_hw_update_ptr hw_update;
122: vga_hw_invalidate_ptr hw_invalidate;
123: vga_hw_screen_dump_ptr hw_screen_dump;
124: void *hw;
125:
126: int g_width, g_height;
127: int width;
128: int height;
129: int total_height;
130: int backscroll_height;
131: int x, y;
132: int x_saved, y_saved;
133: int y_displayed;
134: int y_base;
135: TextAttributes t_attrib_default;
136: TextAttributes t_attrib;
137: TextCell *cells;
138:
139: enum TTYState state;
140: int esc_params[MAX_ESC_PARAMS];
141: int nb_esc_params;
142:
143: CharDriverState *chr;
144:
145: QEMUFIFO out_fifo;
146: uint8_t out_fifo_buf[16];
147: QEMUTimer *kbd_timer;
148: };
149:
150: static TextConsole *active_console;
151: static TextConsole *consoles[MAX_CONSOLES];
152: static int nb_consoles = 0;
153:
154: void vga_hw_update(void)
155: {
156: if (active_console && active_console->hw_update)
157: active_console->hw_update(active_console->hw);
158: }
159:
160: void vga_hw_invalidate(void)
161: {
162: if (active_console->hw_invalidate)
163: active_console->hw_invalidate(active_console->hw);
164: }
165:
166: void vga_hw_screen_dump(const char *filename)
167: {
168:
169:
170: if (consoles[0]->hw_screen_dump)
171: consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
172: }
173:
174:
175: static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
176: {
177: unsigned int r, g, b, color;
178:
179: switch(ds->depth) {
180: #if 0
181: case 8:
182: r = (rgba >> 16) & 0xff;
183: g = (rgba >> 8) & 0xff;
184: b = (rgba) & 0xff;
185: color = (rgb_to_index[r] * 6 * 6) +
186: (rgb_to_index[g] * 6) +
187: (rgb_to_index[b]);
188: break;
189: #endif
190: case 15:
191: r = (rgba >> 16) & 0xff;
192: g = (rgba >> 8) & 0xff;
193: b = (rgba) & 0xff;
194: color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
195: break;
196: case 16:
197: r = (rgba >> 16) & 0xff;
198: g = (rgba >> 8) & 0xff;
199: b = (rgba) & 0xff;
200: color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
201: break;
202: case 32:
203: default:
204: color = rgba;
205: break;
206: }
207: return color;
208: }
209:
210: static void vga_fill_rect (DisplayState *ds,
211: int posx, int posy, int width, int height, uint32_t color)
212: {
213: uint8_t *d, *d1;
214: int x, y, bpp;
215:
216: bpp = (ds->depth + 7) >> 3;
217: d1 = ds->data +
218: ds->linesize * posy + bpp * posx;
219: for (y = 0; y < height; y++) {
220: d = d1;
221: switch(bpp) {
222: case 1:
223: for (x = 0; x < width; x++) {
224: *((uint8_t *)d) = color;
225: d++;
226: }
227: break;
228: case 2:
229: for (x = 0; x < width; x++) {
230: *((uint16_t *)d) = color;
231: d += 2;
232: }
233: break;
234: case 4:
235: for (x = 0; x < width; x++) {
236: *((uint32_t *)d) = color;
237: d += 4;
238: }
239: break;
240: }
241: d1 += ds->linesize;
242: }
243: }
244:
245:
246: static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
247: {
248: const uint8_t *s;
249: uint8_t *d;
250: int wb, y, bpp;
251:
252: bpp = (ds->depth + 7) >> 3;
253: wb = w * bpp;
254: if (yd <= ys) {
255: s = ds->data +
256: ds->linesize * ys + bpp * xs;
257: d = ds->data +
258: ds->linesize * yd + bpp * xd;
259: for (y = 0; y < h; y++) {
260: memmove(d, s, wb);
261: d += ds->linesize;
262: s += ds->linesize;
263: }
264: } else {
265: s = ds->data +
266: ds->linesize * (ys + h - 1) + bpp * xs;
267: d = ds->data +
268: ds->linesize * (yd + h - 1) + bpp * xd;
269: for (y = 0; y < h; y++) {
270: memmove(d, s, wb);
271: d -= ds->linesize;
272: s -= ds->linesize;
273: }
274: }
275: }
276:
277:
278:
279:
280: #define FONT_HEIGHT 16
281: #define FONT_WIDTH 8
282:
283: #include "vgafont.h"
284:
285: #define cbswap_32(__x) \
286: ((uint32_t)( \
287: (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
288: (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
289: (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
290: (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
291:
292: #ifdef WORDS_BIGENDIAN
293: #define PAT(x) x
294: #else
295: #define PAT(x) cbswap_32(x)
296: #endif
297:
298: static const uint32_t dmask16[16] = {
299: PAT(0x00000000),
300: PAT(0x000000ff),
301: PAT(0x0000ff00),
302: PAT(0x0000ffff),
303: PAT(0x00ff0000),
304: PAT(0x00ff00ff),
305: PAT(0x00ffff00),
306: PAT(0x00ffffff),
307: PAT(0xff000000),
308: PAT(0xff0000ff),
309: PAT(0xff00ff00),
310: PAT(0xff00ffff),
311: PAT(0xffff0000),
312: PAT(0xffff00ff),
313: PAT(0xffffff00),
314: PAT(0xffffffff),
315: };
316:
317: static const uint32_t dmask4[4] = {
318: PAT(0x00000000),
319: PAT(0x0000ffff),
320: PAT(0xffff0000),
321: PAT(0xffffffff),
322: };
323:
324: static uint32_t color_table[2][8];
325:
326: enum color_names {
327: COLOR_BLACK = 0,
328: COLOR_RED = 1,
329: COLOR_GREEN = 2,
330: COLOR_YELLOW = 3,
331: COLOR_BLUE = 4,
332: COLOR_MAGENTA = 5,
333: COLOR_CYAN = 6,
334: COLOR_WHITE = 7
335: };
336:
337: static const uint32_t color_table_rgb[2][8] = {
338: {
339: QEMU_RGB(0x00, 0x00, 0x00),
340: QEMU_RGB(0xaa, 0x00, 0x00),
341: QEMU_RGB(0x00, 0xaa, 0x00),
342: QEMU_RGB(0xaa, 0xaa, 0x00),
343: QEMU_RGB(0x00, 0x00, 0xaa),
344: QEMU_RGB(0xaa, 0x00, 0xaa),
345: QEMU_RGB(0x00, 0xaa, 0xaa),
346: QEMU_RGB(0xaa, 0xaa, 0xaa),
347: },
348: {
349: QEMU_RGB(0x00, 0x00, 0x00),
350: QEMU_RGB(0xff, 0x00, 0x00),
351: QEMU_RGB(0x00, 0xff, 0x00),
352: QEMU_RGB(0xff, 0xff, 0x00),
353: QEMU_RGB(0x00, 0x00, 0xff),
354: QEMU_RGB(0xff, 0x00, 0xff),
355: QEMU_RGB(0x00, 0xff, 0xff),
356: QEMU_RGB(0xff, 0xff, 0xff),
357: }
358: };
359:
360: static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
361: {
362: switch(ds->depth) {
363: case 8:
364: col |= col << 8;
365: col |= col << 16;
366: break;
367: case 15:
368: case 16:
369: col |= col << 16;
370: break;
371: default:
372: break;
373: }
374:
375: return col;
376: }
377: #ifdef DEBUG_CONSOLE
378: static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
379: {
380: if (t_attrib->bold) {
381: printf("b");
382: } else {
383: printf(" ");
384: }
385: if (t_attrib->uline) {
386: printf("u");
387: } else {
388: printf(" ");
389: }
390: if (t_attrib->blink) {
391: printf("l");
392: } else {
393: printf(" ");
394: }
395: if (t_attrib->invers) {
396: printf("i");
397: } else {
398: printf(" ");
399: }
400: if (t_attrib->unvisible) {
401: printf("n");
402: } else {
403: printf(" ");
404: }
405:
406: printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
407: }
408: #endif
409:
410: static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
411: TextAttributes *t_attrib)
412: {
413: uint8_t *d;
414: const uint8_t *font_ptr;
415: unsigned int font_data, linesize, xorcol, bpp;
416: int i;
417: unsigned int fgcol, bgcol;
418:
419: #ifdef DEBUG_CONSOLE
420: printf("x: %2i y: %2i", x, y);
421: console_print_text_attributes(t_attrib, ch);
422: #endif
423:
424: if (t_attrib->invers) {
425: bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
426: fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
427: } else {
428: fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
429: bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
430: }
431:
432: bpp = (ds->depth + 7) >> 3;
433: d = ds->data +
434: ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
435: linesize = ds->linesize;
436: font_ptr = vgafont16 + FONT_HEIGHT * ch;
437: xorcol = bgcol ^ fgcol;
438: switch(ds->depth) {
439: case 8:
440: for(i = 0; i < FONT_HEIGHT; i++) {
441: font_data = *font_ptr++;
442: if (t_attrib->uline
443: && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
444: font_data = 0xFFFF;
445: }
446: ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
447: ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
448: d += linesize;
449: }
450: break;
451: case 16:
452: case 15:
453: for(i = 0; i < FONT_HEIGHT; i++) {
454: font_data = *font_ptr++;
455: if (t_attrib->uline
456: && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
457: font_data = 0xFFFF;
458: }
459: ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
460: ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
461: ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
462: ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
463: d += linesize;
464: }
465: break;
466: case 32:
467: for(i = 0; i < FONT_HEIGHT; i++) {
468: font_data = *font_ptr++;
469: if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
470: font_data = 0xFFFF;
471: }
472: ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
473: ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
474: ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
475: ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
476: ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
477: ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
478: ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
479: ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
480: d += linesize;
481: }
482: break;
483: }
484: }
485:
486: static void text_console_resize(TextConsole *s)
487: {
488: TextCell *cells, *c, *c1;
489: int w1, x, y, last_width;
490:
491: last_width = s->width;
492: s->width = s->g_width / FONT_WIDTH;
493: s->height = s->g_height / FONT_HEIGHT;
494:
495: w1 = last_width;
496: if (s->width < w1)
497: w1 = s->width;
498:
499: cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
500: for(y = 0; y < s->total_height; y++) {
501: c = &cells[y * s->width];
502: if (w1 > 0) {
503: c1 = &s->cells[y * last_width];
504: for(x = 0; x < w1; x++) {
505: *c++ = *c1++;
506: }
507: }
508: for(x = w1; x < s->width; x++) {
509: c->ch = ' ';
510: c->t_attrib = s->t_attrib_default;
511: c++;
512: }
513: }
514: qemu_free(s->cells);
515: s->cells = cells;
516: }
517:
518: static void update_xy(TextConsole *s, int x, int y)
519: {
520: TextCell *c;
521: int y1, y2;
522:
523: if (s == active_console) {
524: y1 = (s->y_base + y) % s->total_height;
525: y2 = y1 - s->y_displayed;
526: if (y2 < 0)
527: y2 += s->total_height;
528: if (y2 < s->height) {
529: c = &s->cells[y1 * s->width + x];
530: vga_putcharxy(s->ds, x, y2, c->ch,
531: &(c->t_attrib));
532: dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
533: FONT_WIDTH, FONT_HEIGHT);
534: }
535: }
536: }
537:
538: static void console_show_cursor(TextConsole *s, int show)
539: {
540: TextCell *c;
541: int y, y1;
542:
543: if (s == active_console) {
544: int x = s->x;
545: if (x >= s->width) {
546: x = s->width - 1;
547: }
548: y1 = (s->y_base + s->y) % s->total_height;
549: y = y1 - s->y_displayed;
550: if (y < 0)
551: y += s->total_height;
552: if (y < s->height) {
553: c = &s->cells[y1 * s->width + x];
554: if (show) {
555: TextAttributes t_attrib = s->t_attrib_default;
556: t_attrib.invers = !(t_attrib.invers);
557: vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
558: } else {
559: vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
560: }
561: dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
562: FONT_WIDTH, FONT_HEIGHT);
563: }
5