Annotation of qemu/console.c, revision 1.1.1.12
1.1 root 1: /*
2: * QEMU graphical console
1.1.1.5 root 3: *
1.1 root 4: * Copyright (c) 2004 Fabrice Bellard
1.1.1.5 root 5: *
1.1 root 6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
1.1.1.5 root 24: #include "qemu-common.h"
25: #include "console.h"
26: #include "qemu-timer.h"
1.1 root 27:
1.1.1.2 root 28: //#define DEBUG_CONSOLE
1.1 root 29: #define DEFAULT_BACKSCROLL 512
30: #define MAX_CONSOLES 12
31:
1.1.1.3 root 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)
1.1 root 34:
1.1.1.2 root 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:
1.1 root 45: typedef struct TextCell {
46: uint8_t ch;
1.1.1.2 root 47: TextAttributes t_attrib;
1.1 root 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:
1.1.1.3 root 58: typedef struct QEMUFIFO {
59: uint8_t *buf;
60: int buf_size;
61: int count, wptr, rptr;
62: } QEMUFIFO;
63:
1.1.1.5 root 64: static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
1.1.1.3 root 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:
1.1.1.5 root 87: static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
1.1.1.3 root 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:
1.1.1.5 root 109: typedef enum {
110: GRAPHIC_CONSOLE,
111: TEXT_CONSOLE,
112: TEXT_CONSOLE_FIXED_SIZE
113: } console_type_t;
114:
1.1.1.2 root 115: /* ??? This is mis-named.
116: It is used for both text and graphical consoles. */
1.1 root 117: struct TextConsole {
1.1.1.12! root 118: int index;
1.1.1.5 root 119: console_type_t console_type;
1.1 root 120: DisplayState *ds;
1.1.1.2 root 121: /* Graphic console state. */
122: vga_hw_update_ptr hw_update;
123: vga_hw_invalidate_ptr hw_invalidate;
124: vga_hw_screen_dump_ptr hw_screen_dump;
1.1.1.6 root 125: vga_hw_text_update_ptr hw_text_update;
1.1.1.2 root 126: void *hw;
127:
1.1 root 128: int g_width, g_height;
129: int width;
130: int height;
131: int total_height;
132: int backscroll_height;
133: int x, y;
1.1.1.4 root 134: int x_saved, y_saved;
1.1 root 135: int y_displayed;
136: int y_base;
1.1.1.2 root 137: TextAttributes t_attrib_default; /* default text attributes */
138: TextAttributes t_attrib; /* currently active text attributes */
1.1 root 139: TextCell *cells;
1.1.1.6 root 140: int text_x[2], text_y[2], cursor_invalidate;
1.1.1.10 root 141: int echo;
1.1.1.6 root 142:
143: int update_x0;
144: int update_y0;
145: int update_x1;
146: int update_y1;
1.1 root 147:
148: enum TTYState state;
149: int esc_params[MAX_ESC_PARAMS];
150: int nb_esc_params;
151:
1.1.1.4 root 152: CharDriverState *chr;
1.1.1.3 root 153: /* fifo for key pressed */
154: QEMUFIFO out_fifo;
155: uint8_t out_fifo_buf[16];
156: QEMUTimer *kbd_timer;
1.1 root 157: };
158:
1.1.1.9 root 159: static DisplayState *display_state;
1.1 root 160: static TextConsole *active_console;
161: static TextConsole *consoles[MAX_CONSOLES];
162: static int nb_consoles = 0;
163:
1.1.1.2 root 164: void vga_hw_update(void)
165: {
1.1.1.4 root 166: if (active_console && active_console->hw_update)
1.1.1.2 root 167: active_console->hw_update(active_console->hw);
168: }
169:
170: void vga_hw_invalidate(void)
171: {
1.1.1.9 root 172: if (active_console && active_console->hw_invalidate)
1.1.1.2 root 173: active_console->hw_invalidate(active_console->hw);
174: }
175:
176: void vga_hw_screen_dump(const char *filename)
177: {
1.1.1.6 root 178: TextConsole *previous_active_console;
179:
180: previous_active_console = active_console;
1.1.1.12! root 181:
1.1.1.6 root 182: /* There is currently no way of specifying which screen we want to dump,
183: so always dump the first one. */
1.1.1.12! root 184: console_select(0);
! 185: if (consoles[0] && consoles[0]->hw_screen_dump) {
1.1.1.2 root 186: consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
1.1.1.12! root 187: }
! 188:
! 189: if (previous_active_console) {
! 190: console_select(previous_active_console->index);
! 191: }
1.1.1.6 root 192: }
193:
194: void vga_hw_text_update(console_ch_t *chardata)
195: {
196: if (active_console && active_console->hw_text_update)
197: active_console->hw_text_update(active_console->hw, chardata);
1.1.1.2 root 198: }
199:
1.1 root 200: /* convert a RGBA color to a color index usable in graphic primitives */
201: static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
202: {
203: unsigned int r, g, b, color;
204:
1.1.1.6 root 205: switch(ds_get_bits_per_pixel(ds)) {
1.1 root 206: #if 0
207: case 8:
208: r = (rgba >> 16) & 0xff;
209: g = (rgba >> 8) & 0xff;
210: b = (rgba) & 0xff;
1.1.1.5 root 211: color = (rgb_to_index[r] * 6 * 6) +
212: (rgb_to_index[g] * 6) +
1.1 root 213: (rgb_to_index[b]);
214: break;
215: #endif
216: case 15:
217: r = (rgba >> 16) & 0xff;
218: g = (rgba >> 8) & 0xff;
219: b = (rgba) & 0xff;
220: color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
221: break;
222: case 16:
223: r = (rgba >> 16) & 0xff;
224: g = (rgba >> 8) & 0xff;
225: b = (rgba) & 0xff;
226: color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
227: break;
228: case 32:
229: default:
230: color = rgba;
231: break;
232: }
233: return color;
234: }
235:
1.1.1.5 root 236: static void vga_fill_rect (DisplayState *ds,
1.1 root 237: int posx, int posy, int width, int height, uint32_t color)
238: {
239: uint8_t *d, *d1;
240: int x, y, bpp;
1.1.1.5 root 241:
1.1.1.6 root 242: bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
243: d1 = ds_get_data(ds) +
244: ds_get_linesize(ds) * posy + bpp * posx;
1.1 root 245: for (y = 0; y < height; y++) {
246: d = d1;
247: switch(bpp) {
248: case 1:
249: for (x = 0; x < width; x++) {
250: *((uint8_t *)d) = color;
251: d++;
252: }
253: break;
254: case 2:
255: for (x = 0; x < width; x++) {
256: *((uint16_t *)d) = color;
257: d += 2;
258: }
259: break;
260: case 4:
261: for (x = 0; x < width; x++) {
262: *((uint32_t *)d) = color;
263: d += 4;
264: }
265: break;
266: }
1.1.1.6 root 267: d1 += ds_get_linesize(ds);
1.1 root 268: }
269: }
270:
271: /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
272: static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
273: {
274: const uint8_t *s;
275: uint8_t *d;
276: int wb, y, bpp;
277:
1.1.1.6 root 278: bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
1.1 root 279: wb = w * bpp;
280: if (yd <= ys) {
1.1.1.6 root 281: s = ds_get_data(ds) +
282: ds_get_linesize(ds) * ys + bpp * xs;
283: d = ds_get_data(ds) +
284: ds_get_linesize(ds) * yd + bpp * xd;
1.1 root 285: for (y = 0; y < h; y++) {
286: memmove(d, s, wb);
1.1.1.6 root 287: d += ds_get_linesize(ds);
288: s += ds_get_linesize(ds);
1.1 root 289: }
290: } else {
1.1.1.6 root 291: s = ds_get_data(ds) +
292: ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
293: d = ds_get_data(ds) +
294: ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
1.1 root 295: for (y = 0; y < h; y++) {
296: memmove(d, s, wb);
1.1.1.6 root 297: d -= ds_get_linesize(ds);
298: s -= ds_get_linesize(ds);
1.1 root 299: }
300: }
301: }
302:
303: /***********************************************************/
304: /* basic char display */
305:
306: #define FONT_HEIGHT 16
307: #define FONT_WIDTH 8
308:
309: #include "vgafont.h"
310:
311: #define cbswap_32(__x) \
312: ((uint32_t)( \
313: (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
314: (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
315: (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
316: (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
317:
1.1.1.8 root 318: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 319: #define PAT(x) x
320: #else
321: #define PAT(x) cbswap_32(x)
322: #endif
323:
324: static const uint32_t dmask16[16] = {
325: PAT(0x00000000),
326: PAT(0x000000ff),
327: PAT(0x0000ff00),
328: PAT(0x0000ffff),
329: PAT(0x00ff0000),
330: PAT(0x00ff00ff),
331: PAT(0x00ffff00),
332: PAT(0x00ffffff),
333: PAT(0xff000000),
334: PAT(0xff0000ff),
335: PAT(0xff00ff00),
336: PAT(0xff00ffff),
337: PAT(0xffff0000),
338: PAT(0xffff00ff),
339: PAT(0xffffff00),
340: PAT(0xffffffff),
341: };
342:
343: static const uint32_t dmask4[4] = {
344: PAT(0x00000000),
345: PAT(0x0000ffff),
346: PAT(0xffff0000),
347: PAT(0xffffffff),
348: };
349:
1.1.1.2 root 350: static uint32_t color_table[2][8];
351:
1.1.1.12! root 352: #ifndef CONFIG_CURSES
1.1.1.2 root 353: enum color_names {
354: COLOR_BLACK = 0,
355: COLOR_RED = 1,
356: COLOR_GREEN = 2,
357: COLOR_YELLOW = 3,
358: COLOR_BLUE = 4,
359: COLOR_MAGENTA = 5,
360: COLOR_CYAN = 6,
361: COLOR_WHITE = 7
362: };
1.1.1.12! root 363: #endif
1.1 root 364:
1.1.1.2 root 365: static const uint32_t color_table_rgb[2][8] = {
366: { /* dark */
1.1.1.3 root 367: QEMU_RGB(0x00, 0x00, 0x00), /* black */
368: QEMU_RGB(0xaa, 0x00, 0x00), /* red */
369: QEMU_RGB(0x00, 0xaa, 0x00), /* green */
370: QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
371: QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
372: QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
373: QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
374: QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
1.1.1.2 root 375: },
376: { /* bright */
1.1.1.3 root 377: QEMU_RGB(0x00, 0x00, 0x00), /* black */
378: QEMU_RGB(0xff, 0x00, 0x00), /* red */
379: QEMU_RGB(0x00, 0xff, 0x00), /* green */
380: QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
381: QEMU_RGB(0x00, 0x00, 0xff), /* blue */
382: QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
383: QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
384: QEMU_RGB(0xff, 0xff, 0xff), /* white */
1.1.1.2 root 385: }
1.1 root 386: };
387:
388: static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
389: {
1.1.1.6 root 390: switch(ds_get_bits_per_pixel(ds)) {
1.1 root 391: case 8:
392: col |= col << 8;
393: col |= col << 16;
394: break;
395: case 15:
396: case 16:
397: col |= col << 16;
398: break;
399: default:
400: break;
401: }
402:
403: return col;
404: }
1.1.1.2 root 405: #ifdef DEBUG_CONSOLE
406: static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
407: {
408: if (t_attrib->bold) {
409: printf("b");
410: } else {
411: printf(" ");
412: }
413: if (t_attrib->uline) {
414: printf("u");
415: } else {
416: printf(" ");
417: }
418: if (t_attrib->blink) {
419: printf("l");
420: } else {
421: printf(" ");
422: }
423: if (t_attrib->invers) {
424: printf("i");
425: } else {
426: printf(" ");
427: }
428: if (t_attrib->unvisible) {
429: printf("n");
430: } else {
431: printf(" ");
432: }
433:
434: printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
435: }
436: #endif
1.1 root 437:
1.1.1.5 root 438: static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
1.1.1.2 root 439: TextAttributes *t_attrib)
1.1 root 440: {
441: uint8_t *d;
442: const uint8_t *font_ptr;
443: unsigned int font_data, linesize, xorcol, bpp;
444: int i;
1.1.1.2 root 445: unsigned int fgcol, bgcol;
446:
447: #ifdef DEBUG_CONSOLE
448: printf("x: %2i y: %2i", x, y);
449: console_print_text_attributes(t_attrib, ch);
450: #endif
451:
452: if (t_attrib->invers) {
453: bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
454: fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
455: } else {
456: fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
457: bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
458: }
1.1 root 459:
1.1.1.6 root 460: bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
461: d = ds_get_data(ds) +
462: ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
463: linesize = ds_get_linesize(ds);
1.1 root 464: font_ptr = vgafont16 + FONT_HEIGHT * ch;
465: xorcol = bgcol ^ fgcol;
1.1.1.6 root 466: switch(ds_get_bits_per_pixel(ds)) {
1.1 root 467: case 8:
468: for(i = 0; i < FONT_HEIGHT; i++) {
469: font_data = *font_ptr++;
1.1.1.2 root 470: if (t_attrib->uline
471: && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
1.1.1.12! root 472: font_data = 0xFF;
1.1.1.2 root 473: }
1.1 root 474: ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
475: ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
476: d += linesize;
477: }
478: break;
479: case 16:
480: case 15:
481: for(i = 0; i < FONT_HEIGHT; i++) {
482: font_data = *font_ptr++;
1.1.1.2 root 483: if (t_attrib->uline
484: && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
1.1.1.12! root 485: font_data = 0xFF;
1.1.1.2 root 486: }
1.1 root 487: ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
488: ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
489: ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
490: ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
491: d += linesize;
492: }
493: break;
494: case 32:
495: for(i = 0; i < FONT_HEIGHT; i++) {
496: font_data = *font_ptr++;
1.1.1.2 root 497: if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
1.1.1.12! root 498: font_data = 0xFF;
1.1.1.2 root 499: }
1.1 root 500: ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
501: ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
502: ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
503: ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
504: ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
505: ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
506: ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
507: ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
508: d += linesize;
509: }
510: break;
511: }
512: }
513:
514: static void text_console_resize(TextConsole *s)
515: {
516: TextCell *cells, *c, *c1;
517: int w1, x, y, last_width;
518:
519: last_width = s->width;
520: s->width = s->g_width / FONT_WIDTH;
521: s->height = s->g_height / FONT_HEIGHT;
522:
523: w1 = last_width;
524: if (s->width < w1)
525: w1 = s->width;
526:
1.1.1.12! root 527: cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
1.1 root 528: for(y = 0; y < s->total_height; y++) {
529: c = &cells[y * s->width];
530: if (w1 > 0) {
531: c1 = &s->cells[y * last_width];
532: for(x = 0; x < w1; x++) {
533: *c++ = *c1++;
534: }
535: }
536: for(x = w1; x < s->width; x++) {
537: c->ch = ' ';
1.1.1.2 root 538: c->t_attrib = s->t_attrib_default;
1.1 root 539: c++;
540: }
541: }
1.1.1.12! root 542: g_free(s->cells);
1.1 root 543: s->cells = cells;
544: }
545:
1.1.1.6 root 546: static inline void text_update_xy(TextConsole *s, int x, int y)
547: {
548: s->text_x[0] = MIN(s->text_x[0], x);
549: s->text_x[1] = MAX(s->text_x[1], x);
550: s->text_y[0] = MIN(s->text_y[0], y);
551: s->text_y[1] = MAX(s->text_y[1], y);
552: }
553:
554: static void invalidate_xy(TextConsole *s, int x, int y)
555: {
556: if (s->update_x0 > x * FONT_WIDTH)
557: s->update_x0 = x * FONT_WIDTH;
558: if (s->update_y0 > y * FONT_HEIGHT)
559: s->update_y0 = y * FONT_HEIGHT;
560: if (s->update_x1 < (x + 1) * FONT_WIDTH)
561: s->update_x1 = (x + 1) * FONT_WIDTH;
562: if (s->update_y1 < (y + 1) * FONT_HEIGHT)
563: s->update_y1 = (y + 1) * FONT_HEIGHT;
564: }
565:
1.1 root 566: static void update_xy(TextConsole *s, int x, int y)
567: {
568: TextCell *c;
569: int y1, y2;
570:
571: if (s == active_console) {
1.1.1.6 root 572: if (!ds_get_bits_per_pixel(s->ds)) {
573: text_update_xy(s, x, y);
574: return;
575: }
576:
1.1 root 577: y1 = (s->y_base + y) % s->total_height;
578: y2 = y1 - s->y_displayed;
579: if (y2 < 0)
580: y2 += s->total_height;
581: if (y2 < s->height) {
582: c = &s->cells[y1 * s->width + x];
1.1.1.5 root 583: vga_putcharxy(s->ds, x, y2, c->ch,
1.1.1.2 root 584: &(c->t_attrib));
1.1.1.6 root 585: invalidate_xy(s, x, y2);
1.1 root 586: }
587: }
588: }
589:
590: static void console_show_cursor(TextConsole *s, int show)
591: {
592: TextCell *c;
593: int y, y1;
594:
595: if (s == active_console) {
1.1.1.5 root 596: int x = s->x;
1.1.1.6 root 597:
598: if (!ds_get_bits_per_pixel(s->ds)) {
599: s->cursor_invalidate = 1;
600: return;
601: }
602:
1.1.1.5 root 603: if (x >= s->width) {
604: x = s->width - 1;
605: }
1.1 root 606: y1 = (s->y_base + s->y) % s->total_height;
607: y = y1 - s->y_displayed;
608: if (y < 0)
609: y += s->total_height;
610: if (y < s->height) {
1.1.1.5 root 611: c = &s->cells[y1 * s->width + x];
1.1 root 612: if (show) {
1.1.1.2 root 613: TextAttributes t_attrib = s->t_attrib_default;
614: t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
1.1.1.5 root 615: vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
1.1 root 616: } else {
1.1.1.5 root 617: vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
1.1 root 618: }
1.1.1.6 root 619: invalidate_xy(s, x, y);
1.1 root 620: }
621: }
622: }
623:
624: static void console_refresh(TextConsole *s)
625: {
626: TextCell *c;
627: int x, y, y1;
628:
1.1.1.5 root 629: if (s != active_console)
1.1 root 630: return;
1.1.1.6 root 631: if (!ds_get_bits_per_pixel(s->ds)) {
632: s->text_x[0] = 0;
633: s->text_y[0] = 0;
634: s->text_x[1] = s->width - 1;
635: s->text_y[1] = s->height - 1;
636: s->cursor_invalidate = 1;
637: return;
638: }
1.1 root 639:
1.1.1.6 root 640: vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
1.1.1.2 root 641: color_table[0][COLOR_BLACK]);
1.1 root 642: y1 = s->y_displayed;
643: for(y = 0; y < s->height; y++) {
644: c = s->cells + y1 * s->width;
645: for(x = 0; x < s->width; x++) {
1.1.1.5 root 646: vga_putcharxy(s->ds, x, y, c->ch,
1.1.1.2 root 647: &(c->t_attrib));
1.1 root 648: c++;
649: }
650: if (++y1 == s->total_height)
651: y1 = 0;
652: }
653: console_show_cursor(s, 1);
1.1.1.6 root 654: dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
1.1 root 655: }
656:
657: static void console_scroll(int ydelta)
658: {
659: TextConsole *s;
660: int i, y1;
1.1.1.5 root 661:
1.1 root 662: s = active_console;
1.1.1.5 root 663: if (!s || (s->console_type == GRAPHIC_CONSOLE))
1.1 root 664: return;
665:
666: if (ydelta > 0) {
667: for(i = 0; i < ydelta; i++) {
668: if (s->y_displayed == s->y_base)
669: break;
670: if (++s->y_displayed == s->total_height)
671: s->y_displayed = 0;
672: }
673: } else {
674: ydelta = -ydelta;
675: i = s->backscroll_height;
676: if (i > s->total_height - s->height)
677: i = s->total_height - s->height;
678: y1 = s->y_base - i;
679: if (y1 < 0)
680: y1 += s->total_height;
681: for(i = 0; i < ydelta; i++) {
682: if (s->y_displayed == y1)
683: break;
684: if (--s->y_displayed < 0)
685: s->y_displayed = s->total_height - 1;
686: }
687: }
688: console_refresh(s);
689: }
690:
691: static void console_put_lf(TextConsole *s)
692: {
693: TextCell *c;
694: int x, y1;
695:
696: s->y++;
697: if (s->y >= s->height) {
698: s->y = s->height - 1;
1.1.1.2 root 699:
1.1 root 700: if (s->y_displayed == s->y_base) {
701: if (++s->y_displayed == s->total_height)
702: s->y_displayed = 0;
703: }
704: if (++s->y_base == s->total_height)
705: s->y_base = 0;
706: if (s->backscroll_height < s->total_height)
707: s->backscroll_height++;
708: y1 = (s->y_base + s->height - 1) % s->total_height;
709: c = &s->cells[y1 * s->width];
710: for(x = 0; x < s->width; x++) {
711: c->ch = ' ';
1.1.1.2 root 712: c->t_attrib = s->t_attrib_default;
1.1 root 713: c++;
714: }
715: if (s == active_console && s->y_displayed == s->y_base) {
1.1.1.6 root 716: if (!ds_get_bits_per_pixel(s->ds)) {
717: s->text_x[0] = 0;
718: s->text_y[0] = 0;
719: s->text_x[1] = s->width - 1;
720: s->text_y[1] = s->height - 1;
721: return;
722: }
723:
1.1.1.5 root 724: vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
725: s->width * FONT_WIDTH,
1.1 root 726: (s->height - 1) * FONT_HEIGHT);
727: vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
1.1.1.5 root 728: s->width * FONT_WIDTH, FONT_HEIGHT,
1.1.1.2 root 729: color_table[0][s->t_attrib_default.bgcol]);
1.1.1.6 root 730: s->update_x0 = 0;
731: s->update_y0 = 0;
732: s->update_x1 = s->width * FONT_WIDTH;
733: s->update_y1 = s->height * FONT_HEIGHT;
1.1 root 734: }
735: }
736: }
737:
1.1.1.2 root 738: /* Set console attributes depending on the current escape codes.
739: * NOTE: I know this code is not very efficient (checking every color for it
740: * self) but it is more readable and better maintainable.
741: */
742: static void console_handle_escape(TextConsole *s)
743: {
744: int i;
745:
746: for (i=0; i<s->nb_esc_params; i++) {
747: switch (s->esc_params[i]) {
748: case 0: /* reset all console attributes to default */
749: s->t_attrib = s->t_attrib_default;
750: break;
751: case 1:
752: s->t_attrib.bold = 1;
753: break;
754: case 4:
755: s->t_attrib.uline = 1;
756: break;
757: case 5:
758: s->t_attrib.blink = 1;
759: break;
760: case 7:
761: s->t_attrib.invers = 1;
762: break;
763: case 8:
764: s->t_attrib.unvisible = 1;
765: break;
766: case 22:
767: s->t_attrib.bold = 0;
768: break;
769: case 24:
770: s->t_attrib.uline = 0;
771: break;
772: case 25:
773: s->t_attrib.blink = 0;
774: break;
775: case 27:
776: s->t_attrib.invers = 0;
777: break;
778: case 28:
779: s->t_attrib.unvisible = 0;
780: break;
781: /* set foreground color */
782: case 30:
783: s->t_attrib.fgcol=COLOR_BLACK;
784: break;
785: case 31:
786: s->t_attrib.fgcol=COLOR_RED;
787: break;
788: case 32:
789: s->t_attrib.fgcol=COLOR_GREEN;
790: break;
791: case 33:
792: s->t_attrib.fgcol=COLOR_YELLOW;
793: break;
794: case 34:
795: s->t_attrib.fgcol=COLOR_BLUE;
796: break;
797: case 35:
798: s->t_attrib.fgcol=COLOR_MAGENTA;
799: break;
800: case 36:
801: s->t_attrib.fgcol=COLOR_CYAN;
802: break;
803: case 37:
804: s->t_attrib.fgcol=COLOR_WHITE;
805: break;
806: /* set background color */
807: case 40:
808: s->t_attrib.bgcol=COLOR_BLACK;
809: break;
810: case 41:
811: s->t_attrib.bgcol=COLOR_RED;
812: break;
813: case 42:
814: s->t_attrib.bgcol=COLOR_GREEN;
815: break;
816: case 43:
817: s->t_attrib.bgcol=COLOR_YELLOW;
818: break;
819: case 44:
820: s->t_attrib.bgcol=COLOR_BLUE;
821: break;
822: case 45:
823: s->t_attrib.bgcol=COLOR_MAGENTA;
824: break;
825: case 46:
826: s->t_attrib.bgcol=COLOR_CYAN;
827: break;
828: case 47:
829: s->t_attrib.bgcol=COLOR_WHITE;
830: break;
831: }
832: }
833: }
834:
1.1.1.4 root 835: static void console_clear_xy(TextConsole *s, int x, int y)
836: {
837: int y1 = (s->y_base + y) % s->total_height;
838: TextCell *c = &s->cells[y1 * s->width + x];
839: c->ch = ' ';
840: c->t_attrib = s->t_attrib_default;
841: update_xy(s, x, y);
842: }
843:
1.1 root 844: static void console_putchar(TextConsole *s, int ch)
845: {
846: TextCell *c;
1.1.1.4 root 847: int y1, i;
848: int x, y;
1.1 root 849:
850: switch(s->state) {
851: case TTY_STATE_NORM:
852: switch(ch) {
1.1.1.2 root 853: case '\r': /* carriage return */
1.1 root 854: s->x = 0;
855: break;
1.1.1.2 root 856: case '\n': /* newline */
1.1 root 857: console_put_lf(s);
858: break;
1.1.1.2 root 859: case '\b': /* backspace */
1.1.1.5 root 860: if (s->x > 0)
1.1.1.3 root 861: s->x--;
1.1.1.2 root 862: break;
863: case '\t': /* tabspace */
864: if (s->x + (8 - (s->x % 8)) > s->width) {
1.1.1.3 root 865: s->x = 0;
1.1.1.2 root 866: console_put_lf(s);
867: } else {
868: s->x = s->x + (8 - (s->x % 8));
869: }
870: break;
871: case '\a': /* alert aka. bell */
872: /* TODO: has to be implemented */
873: break;
1.1.1.4 root 874: case 14:
875: /* SI (shift in), character set 0 (ignored) */
876: break;
877: case 15:
878: /* SO (shift out), character set 1 (ignored) */
879: break;
1.1.1.2 root 880: case 27: /* esc (introducing an escape sequence) */
1.1 root 881: s->state = TTY_STATE_ESC;
882: break;
883: default:
1.1.1.5 root 884: if (s->x >= s->width) {
885: /* line wrap */
886: s->x = 0;
887: console_put_lf(s);
1.1.1.4 root 888: }
1.1 root 889: y1 = (s->y_base + s->y) % s->total_height;
890: c = &s->cells[y1 * s->width + s->x];
891: c->ch = ch;
1.1.1.2 root 892: c->t_attrib = s->t_attrib;
1.1 root 893: update_xy(s, s->x, s->y);
894: s->x++;
895: break;
896: }
897: break;
1.1.1.2 root 898: case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
1.1 root 899: if (ch == '[') {
900: for(i=0;i<MAX_ESC_PARAMS;i++)
901: s->esc_params[i] = 0;
902: s->nb_esc_params = 0;
903: s->state = TTY_STATE_CSI;
904: } else {
905: s->state = TTY_STATE_NORM;
906: }
907: break;
1.1.1.2 root 908: case TTY_STATE_CSI: /* handle escape sequence parameters */
1.1 root 909: if (ch >= '0' && ch <= '9') {
910: if (s->nb_esc_params < MAX_ESC_PARAMS) {
1.1.1.5 root 911: s->esc_params[s->nb_esc_params] =
1.1 root 912: s->esc_params[s->nb_esc_params] * 10 + ch - '0';
913: }
914: } else {
915: s->nb_esc_params++;
916: if (ch == ';')
917: break;
1.1.1.4 root 918: #ifdef DEBUG_CONSOLE
919: fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
920: s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
921: #endif
1.1 root 922: s->state = TTY_STATE_NORM;
923: switch(ch) {
1.1.1.4 root 924: case 'A':
925: /* move cursor up */
926: if (s->esc_params[0] == 0) {
927: s->esc_params[0] = 1;
928: }
929: s->y -= s->esc_params[0];
930: if (s->y < 0) {
931: s->y = 0;
932: }
933: break;
934: case 'B':
935: /* move cursor down */
936: if (s->esc_params[0] == 0) {
937: s->esc_params[0] = 1;
938: }
939: s->y += s->esc_params[0];
940: if (s->y >= s->height) {
941: s->y = s->height - 1;
942: }
1.1 root 943: break;
944: case 'C':
1.1.1.4 root 945: /* move cursor right */
946: if (s->esc_params[0] == 0) {
947: s->esc_params[0] = 1;
948: }
949: s->x += s->esc_params[0];
950: if (s->x >= s->width) {
951: s->x = s->width - 1;
952: }
953: break;
954: case 'D':
955: /* move cursor left */
956: if (s->esc_params[0] == 0) {
957: s->esc_params[0] = 1;
958: }
959: s->x -= s->esc_params[0];
960: if (s->x < 0) {
961: s->x = 0;
962: }
963: break;
964: case 'G':
965: /* move cursor to column */
966: s->x = s->esc_params[0] - 1;
967: if (s->x < 0) {
968: s->x = 0;
969: }
970: break;
971: case 'f':
972: case 'H':
973: /* move cursor to row, column */
974: s->x = s->esc_params[1] - 1;
975: if (s->x < 0) {
976: s->x = 0;
977: }
978: s->y = s->esc_params[0] - 1;
979: if (s->y < 0) {
980: s->y = 0;
981: }
982: break;
983: case 'J':
984: switch (s->esc_params[0]) {
985: case 0:
986: /* clear to end of screen */
987: for (y = s->y; y < s->height; y++) {
988: for (x = 0; x < s->width; x++) {
989: if (y == s->y && x < s->x) {
990: continue;
991: }
992: console_clear_xy(s, x, y);
993: }
994: }
995: break;
996: case 1:
997: /* clear from beginning of screen */
998: for (y = 0; y <= s->y; y++) {
999: for (x = 0; x < s->width; x++) {
1000: if (y == s->y && x > s->x) {
1001: break;
1002: }
1003: console_clear_xy(s, x, y);
1004: }
1005: }
1006: break;
1007: case 2:
1008: /* clear entire screen */
1009: for (y = 0; y <= s->height; y++) {
1010: for (x = 0; x < s->width; x++) {
1011: console_clear_xy(s, x, y);
1012: }
1013: }
1.1 root 1014: break;
1.1.1.4 root 1015: }
1.1 root 1016: case 'K':
1.1.1.4 root 1017: switch (s->esc_params[0]) {
1018: case 0:
1.1 root 1019: /* clear to eol */
1020: for(x = s->x; x < s->width; x++) {
1.1.1.4 root 1021: console_clear_xy(s, x, s->y);
1.1 root 1022: }
1023: break;
1.1.1.4 root 1024: case 1:
1025: /* clear from beginning of line */
1026: for (x = 0; x <= s->x; x++) {
1027: console_clear_xy(s, x, s->y);
1028: }
1029: break;
1030: case 2:
1031: /* clear entire line */
1032: for(x = 0; x < s->width; x++) {
1033: console_clear_xy(s, x, s->y);
1034: }
1.1 root 1035: break;
1036: }
1.1.1.4 root 1037: break;
1038: case 'm':
1.1.1.2 root 1039: console_handle_escape(s);
1.1 root 1040: break;
1.1.1.4 root 1041: case 'n':
1042: /* report cursor position */
1043: /* TODO: send ESC[row;colR */
1044: break;
1045: case 's':
1046: /* save cursor position */
1047: s->x_saved = s->x;
1048: s->y_saved = s->y;
1049: break;
1050: case 'u':
1051: /* restore cursor position */
1052: s->x = s->x_saved;
1053: s->y = s->y_saved;
1054: break;
1055: default:
1056: #ifdef DEBUG_CONSOLE
1057: fprintf(stderr, "unhandled escape character '%c'\n", ch);
1058: #endif
1059: break;
1060: }
1061: break;
1.1 root 1062: }
1063: }
1064: }
1065:
1066: void console_select(unsigned int index)
1067: {
1068: TextConsole *s;
1.1.1.2 root 1069:
1.1 root 1070: if (index >= MAX_CONSOLES)
1071: return;
1.1.1.10 root 1072: if (active_console) {
1073: active_console->g_width = ds_get_width(active_console->ds);
1074: active_console->g_height = ds_get_height(active_console->ds);
1075: }
1.1 root 1076: s = consoles[index];
1077: if (s) {
1.1.1.6 root 1078: DisplayState *ds = s->ds;
1.1 root 1079: active_console = s;
1.1.1.6 root 1080: if (ds_get_bits_per_pixel(s->ds)) {
1.1.1.7 root 1081: ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1.1.1.2 root 1082: } else {
1.1.1.6 root 1083: s->ds->surface->width = s->width;
1084: s->ds->surface->height = s->height;
1.1 root 1085: }
1.1.1.6 root 1086: dpy_resize(s->ds);
1087: vga_hw_invalidate();
1.1 root 1088: }
1089: }
1090:
1091: static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1092: {
1093: TextConsole *s = chr->opaque;
1094: int i;
1095:
1.1.1.6 root 1096: s->update_x0 = s->width * FONT_WIDTH;
1097: s->update_y0 = s->height * FONT_HEIGHT;
1098: s->update_x1 = 0;
1099: s->update_y1 = 0;
1.1 root 1100: console_show_cursor(s, 0);
1101: for(i = 0; i < len; i++) {
1102: console_putchar(s, buf[i]);
1103: }
1104: console_show_cursor(s, 1);
1.1.1.6 root 1105: if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1106: dpy_update(s->ds, s->update_x0, s->update_y0,
1107: s->update_x1 - s->update_x0,
1108: s->update_y1 - s->update_y0);
1109: }
1.1 root 1110: return len;
1111: }
1112:
1.1.1.3 root 1113: static void kbd_send_chars(void *opaque)
1114: {
1115: TextConsole *s = opaque;
1116: int len;
1117: uint8_t buf[16];
1.1.1.5 root 1118:
1.1.1.12! root 1119: len = qemu_chr_be_can_write(s->chr);
1.1.1.3 root 1120: if (len > s->out_fifo.count)
1121: len = s->out_fifo.count;
1122: if (len > 0) {
1123: if (len > sizeof(buf))
1124: len = sizeof(buf);
1125: qemu_fifo_read(&s->out_fifo, buf, len);
1.1.1.12! root 1126: qemu_chr_be_write(s->chr, buf, len);
1.1.1.3 root 1127: }
1128: /* characters are pending: we send them a bit later (XXX:
1129: horrible, should change char device API) */
1130: if (s->out_fifo.count > 0) {
1.1.1.11 root 1131: qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1.1.1.3 root 1132: }
1133: }
1134:
1.1 root 1135: /* called when an ascii key is pressed */
1136: void kbd_put_keysym(int keysym)
1137: {
1138: TextConsole *s;
1139: uint8_t buf[16], *q;
1140: int c;
1141:
1142: s = active_console;
1.1.1.5 root 1143: if (!s || (s->console_type == GRAPHIC_CONSOLE))
1.1 root 1144: return;
1145:
1146: switch(keysym) {
1147: case QEMU_KEY_CTRL_UP:
1148: console_scroll(-1);
1149: break;
1150: case QEMU_KEY_CTRL_DOWN:
1151: console_scroll(1);
1152: break;
1153: case QEMU_KEY_CTRL_PAGEUP:
1154: console_scroll(-10);
1155: break;
1156: case QEMU_KEY_CTRL_PAGEDOWN:
1157: console_scroll(10);
1158: break;
1159: default:
1.1.1.3 root 1160: /* convert the QEMU keysym to VT100 key string */
1161: q = buf;
1162: if (keysym >= 0xe100 && keysym <= 0xe11f) {
1163: *q++ = '\033';
1164: *q++ = '[';
1165: c = keysym - 0xe100;
1166: if (c >= 10)
1167: *q++ = '0' + (c / 10);
1168: *q++ = '0' + (c % 10);
1169: *q++ = '~';
1170: } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1171: *q++ = '\033';
1172: *q++ = '[';
1173: *q++ = keysym & 0xff;
1.1.1.10 root 1174: } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1175: console_puts(s->chr, (const uint8_t *) "\r", 1);
1176: *q++ = '\n';
1.1.1.3 root 1177: } else {
1.1.1.10 root 1178: *q++ = keysym;
1179: }
1180: if (s->echo) {
1181: console_puts(s->chr, buf, q - buf);
1.1.1.3 root 1182: }
1.1.1.4 root 1183: if (s->chr->chr_read) {
1.1.1.3 root 1184: qemu_fifo_write(&s->out_fifo, buf, q - buf);
1185: kbd_send_chars(s);
1.1 root 1186: }
1187: break;
1188: }
1189: }
1190:
1.1.1.6 root 1191: static void text_console_invalidate(void *opaque)
1192: {
1193: TextConsole *s = (TextConsole *) opaque;
1194: if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1195: s->g_width = ds_get_width(s->ds);
1196: s->g_height = ds_get_height(s->ds);
1197: text_console_resize(s);
1198: }
1199: console_refresh(s);
1200: }
1201:
1202: static void text_console_update(void *opaque, console_ch_t *chardata)
1203: {
1204: TextConsole *s = (TextConsole *) opaque;
1205: int i, j, src;
1206:
1207: if (s->text_x[0] <= s->text_x[1]) {
1208: src = (s->y_base + s->text_y[0]) * s->width;
1209: chardata += s->text_y[0] * s->width;
1210: for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1211: for (j = 0; j < s->width; j ++, src ++)
1212: console_write_ch(chardata ++, s->cells[src].ch |
1213: (s->cells[src].t_attrib.fgcol << 12) |
1214: (s->cells[src].t_attrib.bgcol << 8) |
1215: (s->cells[src].t_attrib.bold << 21));
1216: dpy_update(s->ds, s->text_x[0], s->text_y[0],
1217: s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1218: s->text_x[0] = s->width;
1219: s->text_y[0] = s->height;
1220: s->text_x[1] = 0;
1221: s->text_y[1] = 0;
1222: }
1223: if (s->cursor_invalidate) {
1224: dpy_cursor(s->ds, s->x, s->y);
1225: s->cursor_invalidate = 0;
1226: }
1227: }
1228:
1229: static TextConsole *get_graphic_console(DisplayState *ds)
1230: {
1231: int i;
1232: TextConsole *s;
1233: for (i = 0; i < nb_consoles; i++) {
1234: s = consoles[i];
1235: if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1236: return s;
1237: }
1238: return NULL;
1239: }
1240:
1.1.1.5 root 1241: static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1.1 root 1242: {
1243: TextConsole *s;
1.1.1.2 root 1244: int i;
1.1 root 1245:
1246: if (nb_consoles >= MAX_CONSOLES)
1247: return NULL;
1.1.1.12! root 1248: s = g_malloc0(sizeof(TextConsole));
1.1.1.5 root 1249: if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1250: (console_type == GRAPHIC_CONSOLE))) {
1.1 root 1251: active_console = s;
1.1.1.5 root 1252: }
1.1 root 1253: s->ds = ds;
1.1.1.5 root 1254: s->console_type = console_type;
1255: if (console_type != GRAPHIC_CONSOLE) {
1.1.1.12! root 1256: s->index = nb_consoles;
1.1.1.2 root 1257: consoles[nb_consoles++] = s;
1258: } else {
1259: /* HACK: Put graphical consoles before text consoles. */
1260: for (i = nb_consoles; i > 0; i--) {
1.1.1.5 root 1261: if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1.1.1.2 root 1262: break;
1263: consoles[i] = consoles[i - 1];
1.1.1.12! root 1264: consoles[i]->index = i;
1.1.1.2 root 1265: }
1.1.1.12! root 1266: s->index = i;
1.1.1.2 root 1267: consoles[i] = s;
1.1.1.6 root 1268: nb_consoles++;
1.1.1.2 root 1269: }
1270: return s;
1271: }
1272:
1.1.1.9 root 1273: static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1274: {
1.1.1.12! root 1275: DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1.1.1.9 root 1276:
1.1.1.11 root 1277: int linesize = width * 4;
1278: qemu_alloc_display(surface, width, height, linesize,
1279: qemu_default_pixelformat(32), 0);
1.1.1.9 root 1280: return surface;
1281: }
1282:
1283: static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1284: int width, int height)
1285: {
1.1.1.11 root 1286: int linesize = width * 4;
1287: qemu_alloc_display(surface, width, height, linesize,
1288: qemu_default_pixelformat(32), 0);
1289: return surface;
1290: }
1291:
1292: void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1293: int linesize, PixelFormat pf, int newflags)
1294: {
1295: void *data;
1.1.1.9 root 1296: surface->width = width;
1297: surface->height = height;
1.1.1.11 root 1298: surface->linesize = linesize;
1299: surface->pf = pf;
1300: if (surface->flags & QEMU_ALLOCATED_FLAG) {
1.1.1.12! root 1301: data = g_realloc(surface->data,
1.1.1.11 root 1302: surface->linesize * surface->height);
1303: } else {
1.1.1.12! root 1304: data = g_malloc(surface->linesize * surface->height);
1.1.1.11 root 1305: }
1306: surface->data = (uint8_t *)data;
1307: surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1.1.1.9 root 1308: #ifdef HOST_WORDS_BIGENDIAN
1.1.1.11 root 1309: surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1.1.1.9 root 1310: #endif
1311: }
1312:
1313: DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1314: int linesize, uint8_t *data)
1315: {
1.1.1.12! root 1316: DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1.1.1.9 root 1317:
1318: surface->width = width;
1319: surface->height = height;
1320: surface->linesize = linesize;
1321: surface->pf = qemu_default_pixelformat(bpp);
1322: #ifdef HOST_WORDS_BIGENDIAN
1323: surface->flags = QEMU_BIG_ENDIAN_FLAG;
1324: #endif
1325: surface->data = data;
1326:
1327: return surface;
1328: }
1329:
1330: static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1331: {
1332: if (surface == NULL)
1333: return;
1334: if (surface->flags & QEMU_ALLOCATED_FLAG)
1.1.1.12! root 1335: g_free(surface->data);
! 1336: g_free(surface);
1.1.1.9 root 1337: }
1338:
1339: static struct DisplayAllocator default_allocator = {
1340: defaultallocator_create_displaysurface,
1341: defaultallocator_resize_displaysurface,
1342: defaultallocator_free_displaysurface
1343: };
1344:
1345: static void dumb_display_init(void)
1346: {
1.1.1.12! root 1347: DisplayState *ds = g_malloc0(sizeof(DisplayState));
1.1.1.11 root 1348: int width = 640;
1349: int height = 480;
1350:
1.1.1.9 root 1351: ds->allocator = &default_allocator;
1.1.1.11 root 1352: if (is_fixedsize_console()) {
1353: width = active_console->g_width;
1354: height = active_console->g_height;
1355: }
1356: ds->surface = qemu_create_displaysurface(ds, width, height);
1.1.1.9 root 1357: register_displaystate(ds);
1358: }
1359:
1360: /***********************************************************/
1361: /* register display */
1362:
1363: void register_displaystate(DisplayState *ds)
1364: {
1365: DisplayState **s;
1366: s = &display_state;
1367: while (*s != NULL)
1368: s = &(*s)->next;
1369: ds->next = NULL;
1370: *s = ds;
1371: }
1372:
1373: DisplayState *get_displaystate(void)
1374: {
1375: if (!display_state) {
1376: dumb_display_init ();
1377: }
1378: return display_state;
1379: }
1380:
1381: DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1382: {
1383: if(ds->allocator == &default_allocator) {
1384: DisplaySurface *surf;
1385: surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1386: defaultallocator_free_displaysurface(ds->surface);
1387: ds->surface = surf;
1388: ds->allocator = da;
1389: }
1390: return ds->allocator;
1391: }
1392:
1.1.1.6 root 1393: DisplayState *graphic_console_init(vga_hw_update_ptr update,
1394: vga_hw_invalidate_ptr invalidate,
1395: vga_hw_screen_dump_ptr screen_dump,
1396: vga_hw_text_update_ptr text_update,
1397: void *opaque)
1.1.1.2 root 1398: {
1399: TextConsole *s;
1.1.1.6 root 1400: DisplayState *ds;
1401:
1.1.1.12! root 1402: ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1.1.1.7 root 1403: ds->allocator = &default_allocator;
1404: ds->surface = qemu_create_displaysurface(ds, 640, 480);
1.1.1.2 root 1405:
1.1.1.5 root 1406: s = new_console(ds, GRAPHIC_CONSOLE);
1.1.1.6 root 1407: if (s == NULL) {
1.1.1.7 root 1408: qemu_free_displaysurface(ds);
1.1.1.12! root 1409: g_free(ds);
1.1.1.6 root 1410: return NULL;
1411: }
1.1.1.2 root 1412: s->hw_update = update;
1413: s->hw_invalidate = invalidate;
1414: s->hw_screen_dump = screen_dump;
1.1.1.6 root 1415: s->hw_text_update = text_update;
1.1.1.2 root 1416: s->hw = opaque;
1.1.1.6 root 1417:
1418: register_displaystate(ds);
1419: return ds;
1.1 root 1420: }
1421:
1.1.1.2 root 1422: int is_graphic_console(void)
1.1 root 1423: {
1.1.1.6 root 1424: return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1425: }
1426:
1427: int is_fixedsize_console(void)
1428: {
1429: return active_console && active_console->console_type != TEXT_CONSOLE;
1.1 root 1430: }
1431:
1.1.1.5 root 1432: void console_color_init(DisplayState *ds)
1433: {
1434: int i, j;
1435: for (j = 0; j < 2; j++) {
1436: for (i = 0; i < 8; i++) {
1.1.1.6 root 1437: color_table[j][i] = col_expand(ds,
1.1.1.5 root 1438: vga_get_color(ds, color_table_rgb[j][i]));
1439: }
1440: }
1441: }
1442:
1.1.1.6 root 1443: static int n_text_consoles;
1444: static CharDriverState *text_consoles[128];
1445:
1.1.1.10 root 1446: static void text_console_set_echo(CharDriverState *chr, bool echo)
1.1 root 1447: {
1.1.1.10 root 1448: TextConsole *s = chr->opaque;
1.1.1.2 root 1449:
1.1.1.10 root 1450: s->echo = echo;
1451: }
1.1.1.8 root 1452:
1.1.1.10 root 1453: static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1454: {
1455: TextConsole *s;
1456: static int color_inited;
1.1.1.8 root 1457:
1.1.1.10 root 1458: s = chr->opaque;
1.1.1.8 root 1459:
1.1 root 1460: chr->chr_write = console_puts;
1461:
1.1.1.3 root 1462: s->out_fifo.buf = s->out_fifo_buf;
1463: s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1.1.1.11 root 1464: s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1.1.1.6 root 1465: s->ds = ds;
1.1.1.5 root 1466:
1.1 root 1467: if (!color_inited) {
1468: color_inited = 1;
1.1.1.5 root 1469: console_color_init(s->ds);
1.1 root 1470: }
1471: s->y_displayed = 0;
1472: s->y_base = 0;
1473: s->total_height = DEFAULT_BACKSCROLL;
1474: s->x = 0;
1475: s->y = 0;
1.1.1.10 root 1476: if (s->console_type == TEXT_CONSOLE) {
1477: s->g_width = ds_get_width(s->ds);
1478: s->g_height = ds_get_height(s->ds);
1479: }
1.1.1.2 root 1480:
1.1.1.6 root 1481: s->hw_invalidate = text_console_invalidate;
1482: s->hw_text_update = text_console_update;
1483: s->hw = s;
1484:
1.1.1.2 root 1485: /* Set text attribute defaults */
1486: s->t_attrib_default.bold = 0;
1487: s->t_attrib_default.uline = 0;
1488: s->t_attrib_default.blink = 0;
1489: s->t_attrib_default.invers = 0;
1490: s->t_attrib_default.unvisible = 0;
1491: s->t_attrib_default.fgcol = COLOR_WHITE;
1492: s->t_attrib_default.bgcol = COLOR_BLACK;
1493: /* set current text attributes to default */
1494: s->t_attrib = s->t_attrib_default;
1.1 root 1495: text_console_resize(s);
1496:
1.1.1.8 root 1497: if (chr->label) {
1498: char msg[128];
1499: int len;
1500:
1501: s->t_attrib.bgcol = COLOR_BLUE;
1502: len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1503: console_puts(chr, (uint8_t*)msg, len);
1504: s->t_attrib = s->t_attrib_default;
1505: }
1506:
1507: qemu_chr_generic_open(chr);
1.1.1.6 root 1508: if (chr->init)
1509: chr->init(chr);
1510: }
1511:
1.1.1.11 root 1512: int text_console_init(QemuOpts *opts, CharDriverState **_chr)
1.1.1.6 root 1513: {
1514: CharDriverState *chr;
1.1.1.10 root 1515: TextConsole *s;
1516: unsigned width;
1517: unsigned height;
1.1.1.6 root 1518:
1.1.1.12! root 1519: chr = g_malloc0(sizeof(CharDriverState));
1.1.1.6 root 1520:
1521: if (n_text_consoles == 128) {
1522: fprintf(stderr, "Too many text consoles\n");
1523: exit(1);
1524: }
1525: text_consoles[n_text_consoles] = chr;
1526: n_text_consoles++;
1.1.1.4 root 1527:
1.1.1.10 root 1528: width = qemu_opt_get_number(opts, "width", 0);
1529: if (width == 0)
1530: width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1531:
1532: height = qemu_opt_get_number(opts, "height", 0);
1533: if (height == 0)
1534: height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1535:
1536: if (width == 0 || height == 0) {
1537: s = new_console(NULL, TEXT_CONSOLE);
1538: } else {
1539: s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1540: }
1541:
1542: if (!s) {
1.1.1.12! root 1543: g_free(chr);
1.1.1.11 root 1544: return -EBUSY;
1.1.1.10 root 1545: }
1546:
1547: s->chr = chr;
1548: s->g_width = width;
1549: s->g_height = height;
1550: chr->opaque = s;
1551: chr->chr_set_echo = text_console_set_echo;
1.1.1.11 root 1552:
1553: *_chr = chr;
1554: return 0;
1.1 root 1555: }
1.1.1.6 root 1556:
1557: void text_consoles_set_display(DisplayState *ds)
1558: {
1559: int i;
1560:
1561: for (i = 0; i < n_text_consoles; i++) {
1.1.1.10 root 1562: text_console_do_init(text_consoles[i], ds);
1.1.1.6 root 1563: }
1564:
1565: n_text_consoles = 0;
1566: }
1567:
1568: void qemu_console_resize(DisplayState *ds, int width, int height)
1569: {
1570: TextConsole *s = get_graphic_console(ds);
1571: if (!s) return;
1572:
1573: s->g_width = width;
1574: s->g_height = height;
1575: if (is_graphic_console()) {
1.1.1.7 root 1576: ds->surface = qemu_resize_displaysurface(ds, width, height);
1.1.1.6 root 1577: dpy_resize(ds);
1578: }
1579: }
1580:
1581: void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1582: int dst_x, int dst_y, int w, int h)
1583: {
1584: if (is_graphic_console()) {
1585: dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1586: }
1587: }
1588:
1589: PixelFormat qemu_different_endianness_pixelformat(int bpp)
1590: {
1591: PixelFormat pf;
1592:
1593: memset(&pf, 0x00, sizeof(PixelFormat));
1594:
1595: pf.bits_per_pixel = bpp;
1596: pf.bytes_per_pixel = bpp / 8;
1597: pf.depth = bpp == 32 ? 24 : bpp;
1598:
1599: switch (bpp) {
1600: case 24:
1601: pf.rmask = 0x000000FF;
1602: pf.gmask = 0x0000FF00;
1603: pf.bmask = 0x00FF0000;
1604: pf.rmax = 255;
1605: pf.gmax = 255;
1606: pf.bmax = 255;
1607: pf.rshift = 0;
1608: pf.gshift = 8;
1609: pf.bshift = 16;
1610: pf.rbits = 8;
1611: pf.gbits = 8;
1612: pf.bbits = 8;
1613: break;
1614: case 32:
1615: pf.rmask = 0x0000FF00;
1616: pf.gmask = 0x00FF0000;
1617: pf.bmask = 0xFF000000;
1618: pf.amask = 0x00000000;
1619: pf.amax = 255;
1620: pf.rmax = 255;
1621: pf.gmax = 255;
1622: pf.bmax = 255;
1623: pf.ashift = 0;
1624: pf.rshift = 8;
1625: pf.gshift = 16;
1626: pf.bshift = 24;
1627: pf.rbits = 8;
1628: pf.gbits = 8;
1629: pf.bbits = 8;
1630: pf.abits = 8;
1631: break;
1632: default:
1633: break;
1634: }
1635: return pf;
1636: }
1637:
1638: PixelFormat qemu_default_pixelformat(int bpp)
1639: {
1640: PixelFormat pf;
1641:
1642: memset(&pf, 0x00, sizeof(PixelFormat));
1643:
1644: pf.bits_per_pixel = bpp;
1645: pf.bytes_per_pixel = bpp / 8;
1646: pf.depth = bpp == 32 ? 24 : bpp;
1647:
1648: switch (bpp) {
1.1.1.9 root 1649: case 15:
1650: pf.bits_per_pixel = 16;
1651: pf.bytes_per_pixel = 2;
1652: pf.rmask = 0x00007c00;
1653: pf.gmask = 0x000003E0;
1654: pf.bmask = 0x0000001F;
1655: pf.rmax = 31;
1656: pf.gmax = 31;
1657: pf.bmax = 31;
1658: pf.rshift = 10;
1659: pf.gshift = 5;
1660: pf.bshift = 0;
1661: pf.rbits = 5;
1662: pf.gbits = 5;
1663: pf.bbits = 5;
1664: break;
1.1.1.6 root 1665: case 16:
1666: pf.rmask = 0x0000F800;
1667: pf.gmask = 0x000007E0;
1668: pf.bmask = 0x0000001F;
1669: pf.rmax = 31;
1670: pf.gmax = 63;
1671: pf.bmax = 31;
1672: pf.rshift = 11;
1673: pf.gshift = 5;
1674: pf.bshift = 0;
1675: pf.rbits = 5;
1676: pf.gbits = 6;
1677: pf.bbits = 5;
1678: break;
1679: case 24:
1680: pf.rmask = 0x00FF0000;
1681: pf.gmask = 0x0000FF00;
1682: pf.bmask = 0x000000FF;
1683: pf.rmax = 255;
1684: pf.gmax = 255;
1685: pf.bmax = 255;
1686: pf.rshift = 16;
1687: pf.gshift = 8;
1688: pf.bshift = 0;
1689: pf.rbits = 8;
1690: pf.gbits = 8;
1691: pf.bbits = 8;
1692: case 32:
1693: pf.rmask = 0x00FF0000;
1694: pf.gmask = 0x0000FF00;
1695: pf.bmask = 0x000000FF;
1696: pf.amax = 255;
1697: pf.rmax = 255;
1698: pf.gmax = 255;
1699: pf.bmax = 255;
1700: pf.ashift = 24;
1701: pf.rshift = 16;
1702: pf.gshift = 8;
1703: pf.bshift = 0;
1704: pf.rbits = 8;
1705: pf.gbits = 8;
1706: pf.bbits = 8;
1707: pf.abits = 8;
1708: break;
1709: default:
1710: break;
1711: }
1712: return pf;
1713: }
unix.superglobalmegacorp.com