DisplayState interface change (Stefano Stabellini)
[qemu] / console.c
1 /*
2  * QEMU graphical console
3  *
4  * Copyright (c) 2004 Fabrice Bellard
5  *
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  */
24 #include "qemu-common.h"
25 #include "console.h"
26 #include "qemu-timer.h"
27
28 //#define DEBUG_CONSOLE
29 #define DEFAULT_BACKSCROLL 512
30 #define MAX_CONSOLES 12
31 #define DEFAULT_MONITOR_SIZE "800x600"
32
33 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
34 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
35
36 typedef struct TextAttributes {
37     uint8_t fgcol:4;
38     uint8_t bgcol:4;
39     uint8_t bold:1;
40     uint8_t uline:1;
41     uint8_t blink:1;
42     uint8_t invers:1;
43     uint8_t unvisible:1;
44 } TextAttributes;
45
46 typedef struct TextCell {
47     uint8_t ch;
48     TextAttributes t_attrib;
49 } TextCell;
50
51 #define MAX_ESC_PARAMS 3
52
53 enum TTYState {
54     TTY_STATE_NORM,
55     TTY_STATE_ESC,
56     TTY_STATE_CSI,
57 };
58
59 typedef struct QEMUFIFO {
60     uint8_t *buf;
61     int buf_size;
62     int count, wptr, rptr;
63 } QEMUFIFO;
64
65 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
66 {
67     int l, len;
68
69     l = f->buf_size - f->count;
70     if (len1 > l)
71         len1 = l;
72     len = len1;
73     while (len > 0) {
74         l = f->buf_size - f->wptr;
75         if (l > len)
76             l = len;
77         memcpy(f->buf + f->wptr, buf, l);
78         f->wptr += l;
79         if (f->wptr >= f->buf_size)
80             f->wptr = 0;
81         buf += l;
82         len -= l;
83     }
84     f->count += len1;
85     return len1;
86 }
87
88 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
89 {
90     int l, len;
91
92     if (len1 > f->count)
93         len1 = f->count;
94     len = len1;
95     while (len > 0) {
96         l = f->buf_size - f->rptr;
97         if (l > len)
98             l = len;
99         memcpy(buf, f->buf + f->rptr, l);
100         f->rptr += l;
101         if (f->rptr >= f->buf_size)
102             f->rptr = 0;
103         buf += l;
104         len -= l;
105     }
106     f->count -= len1;
107     return len1;
108 }
109
110 typedef enum {
111     GRAPHIC_CONSOLE,
112     TEXT_CONSOLE,
113     TEXT_CONSOLE_FIXED_SIZE
114 } console_type_t;
115
116 /* ??? This is mis-named.
117    It is used for both text and graphical consoles.  */
118 struct TextConsole {
119     console_type_t console_type;
120     DisplayState *ds;
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;
125     vga_hw_text_update_ptr hw_text_update;
126     void *hw;
127
128     int g_width, g_height;
129     int width;
130     int height;
131     int total_height;
132     int backscroll_height;
133     int x, y;
134     int x_saved, y_saved;
135     int y_displayed;
136     int y_base;
137     TextAttributes t_attrib_default; /* default text attributes */
138     TextAttributes t_attrib; /* currently active text attributes */
139     TextCell *cells;
140     int text_x[2], text_y[2], cursor_invalidate;
141
142     enum TTYState state;
143     int esc_params[MAX_ESC_PARAMS];
144     int nb_esc_params;
145
146     CharDriverState *chr;
147     /* fifo for key pressed */
148     QEMUFIFO out_fifo;
149     uint8_t out_fifo_buf[16];
150     QEMUTimer *kbd_timer;
151 };
152
153 static TextConsole *active_console;
154 static TextConsole *consoles[MAX_CONSOLES];
155 static int nb_consoles = 0;
156
157 void vga_hw_update(void)
158 {
159     if (active_console && active_console->hw_update)
160         active_console->hw_update(active_console->hw);
161 }
162
163 void vga_hw_invalidate(void)
164 {
165     if (active_console->hw_invalidate)
166         active_console->hw_invalidate(active_console->hw);
167 }
168
169 void vga_hw_screen_dump(const char *filename)
170 {
171     TextConsole *previous_active_console;
172
173     previous_active_console = active_console;
174     active_console = consoles[0];
175     /* There is currently no way of specifying which screen we want to dump,
176        so always dump the first one.  */
177     if (consoles[0]->hw_screen_dump)
178         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
179     active_console = previous_active_console;
180 }
181
182 void vga_hw_text_update(console_ch_t *chardata)
183 {
184     if (active_console && active_console->hw_text_update)
185         active_console->hw_text_update(active_console->hw, chardata);
186 }
187
188 /* convert a RGBA color to a color index usable in graphic primitives */
189 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
190 {
191     unsigned int r, g, b, color;
192
193     switch(ds_get_bits_per_pixel(ds)) {
194 #if 0
195     case 8:
196         r = (rgba >> 16) & 0xff;
197         g = (rgba >> 8) & 0xff;
198         b = (rgba) & 0xff;
199         color = (rgb_to_index[r] * 6 * 6) +
200             (rgb_to_index[g] * 6) +
201             (rgb_to_index[b]);
202         break;
203 #endif
204     case 15:
205         r = (rgba >> 16) & 0xff;
206         g = (rgba >> 8) & 0xff;
207         b = (rgba) & 0xff;
208         color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
209         break;
210     case 16:
211         r = (rgba >> 16) & 0xff;
212         g = (rgba >> 8) & 0xff;
213         b = (rgba) & 0xff;
214         color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
215         break;
216     case 32:
217     default:
218         color = rgba;
219         break;
220     }
221     return color;
222 }
223
224 static void vga_fill_rect (DisplayState *ds,
225                            int posx, int posy, int width, int height, uint32_t color)
226 {
227     uint8_t *d, *d1;
228     int x, y, bpp;
229
230     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
231     d1 = ds_get_data(ds) +
232         ds_get_linesize(ds) * posy + bpp * posx;
233     for (y = 0; y < height; y++) {
234         d = d1;
235         switch(bpp) {
236         case 1:
237             for (x = 0; x < width; x++) {
238                 *((uint8_t *)d) = color;
239                 d++;
240             }
241             break;
242         case 2:
243             for (x = 0; x < width; x++) {
244                 *((uint16_t *)d) = color;
245                 d += 2;
246             }
247             break;
248         case 4:
249             for (x = 0; x < width; x++) {
250                 *((uint32_t *)d) = color;
251                 d += 4;
252             }
253             break;
254         }
255         d1 += ds_get_linesize(ds);
256     }
257 }
258
259 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
260 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
261 {
262     const uint8_t *s;
263     uint8_t *d;
264     int wb, y, bpp;
265
266     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
267     wb = w * bpp;
268     if (yd <= ys) {
269         s = ds_get_data(ds) +
270             ds_get_linesize(ds) * ys + bpp * xs;
271         d = ds_get_data(ds) +
272             ds_get_linesize(ds) * yd + bpp * xd;
273         for (y = 0; y < h; y++) {
274             memmove(d, s, wb);
275             d += ds_get_linesize(ds);
276             s += ds_get_linesize(ds);
277         }
278     } else {
279         s = ds_get_data(ds) +
280             ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
281         d = ds_get_data(ds) +
282             ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
283        for (y = 0; y < h; y++) {
284             memmove(d, s, wb);
285             d -= ds_get_linesize(ds);
286             s -= ds_get_linesize(ds);
287         }
288     }
289 }
290
291 /***********************************************************/
292 /* basic char display */
293
294 #define FONT_HEIGHT 16
295 #define FONT_WIDTH 8
296
297 #include "vgafont.h"
298
299 #define cbswap_32(__x) \
300 ((uint32_t)( \
301                 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
302                 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
303                 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
304                 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
305
306 #ifdef WORDS_BIGENDIAN
307 #define PAT(x) x
308 #else
309 #define PAT(x) cbswap_32(x)
310 #endif
311
312 static const uint32_t dmask16[16] = {
313     PAT(0x00000000),
314     PAT(0x000000ff),
315     PAT(0x0000ff00),
316     PAT(0x0000ffff),
317     PAT(0x00ff0000),
318     PAT(0x00ff00ff),
319     PAT(0x00ffff00),
320     PAT(0x00ffffff),
321     PAT(0xff000000),
322     PAT(0xff0000ff),
323     PAT(0xff00ff00),
324     PAT(0xff00ffff),
325     PAT(0xffff0000),
326     PAT(0xffff00ff),
327     PAT(0xffffff00),
328     PAT(0xffffffff),
329 };
330
331 static const uint32_t dmask4[4] = {
332     PAT(0x00000000),
333     PAT(0x0000ffff),
334     PAT(0xffff0000),
335     PAT(0xffffffff),
336 };
337
338 static uint32_t color_table[2][8];
339
340 enum color_names {
341     COLOR_BLACK   = 0,
342     COLOR_RED     = 1,
343     COLOR_GREEN   = 2,
344     COLOR_YELLOW  = 3,
345     COLOR_BLUE    = 4,
346     COLOR_MAGENTA = 5,
347     COLOR_CYAN    = 6,
348     COLOR_WHITE   = 7
349 };
350
351 static const uint32_t color_table_rgb[2][8] = {
352     {   /* dark */
353         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
354         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
355         QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
356         QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
357         QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
358         QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
359         QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
360         QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
361     },
362     {   /* bright */
363         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
364         QEMU_RGB(0xff, 0x00, 0x00),  /* red */
365         QEMU_RGB(0x00, 0xff, 0x00),  /* green */
366         QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
367         QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
368         QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
369         QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
370         QEMU_RGB(0xff, 0xff, 0xff),  /* white */
371     }
372 };
373
374 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
375 {
376     switch(ds_get_bits_per_pixel(ds)) {
377     case 8:
378         col |= col << 8;
379         col |= col << 16;
380         break;
381     case 15:
382     case 16:
383         col |= col << 16;
384         break;
385     default:
386         break;
387     }
388
389     return col;
390 }
391 #ifdef DEBUG_CONSOLE
392 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
393 {
394     if (t_attrib->bold) {
395         printf("b");
396     } else {
397         printf(" ");
398     }
399     if (t_attrib->uline) {
400         printf("u");
401     } else {
402         printf(" ");
403     }
404     if (t_attrib->blink) {
405         printf("l");
406     } else {
407         printf(" ");
408     }
409     if (t_attrib->invers) {
410         printf("i");
411     } else {
412         printf(" ");
413     }
414     if (t_attrib->unvisible) {
415         printf("n");
416     } else {
417         printf(" ");
418     }
419
420     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
421 }
422 #endif
423
424 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
425                           TextAttributes *t_attrib)
426 {
427     uint8_t *d;
428     const uint8_t *font_ptr;
429     unsigned int font_data, linesize, xorcol, bpp;
430     int i;
431     unsigned int fgcol, bgcol;
432
433 #ifdef DEBUG_CONSOLE
434     printf("x: %2i y: %2i", x, y);
435     console_print_text_attributes(t_attrib, ch);
436 #endif
437
438     if (t_attrib->invers) {
439         bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
440         fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
441     } else {
442         fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
443         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
444     }
445
446     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
447     d = ds_get_data(ds) +
448         ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
449     linesize = ds_get_linesize(ds);
450     font_ptr = vgafont16 + FONT_HEIGHT * ch;
451     xorcol = bgcol ^ fgcol;
452     switch(ds_get_bits_per_pixel(ds)) {
453     case 8:
454         for(i = 0; i < FONT_HEIGHT; i++) {
455             font_data = *font_ptr++;
456             if (t_attrib->uline
457                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
458                 font_data = 0xFFFF;
459             }
460             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
461             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
462             d += linesize;
463         }
464         break;
465     case 16:
466     case 15:
467         for(i = 0; i < FONT_HEIGHT; i++) {
468             font_data = *font_ptr++;
469             if (t_attrib->uline
470                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
471                 font_data = 0xFFFF;
472             }
473             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
474             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
475             ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
476             ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
477             d += linesize;
478         }
479         break;
480     case 32:
481         for(i = 0; i < FONT_HEIGHT; i++) {
482             font_data = *font_ptr++;
483             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
484                 font_data = 0xFFFF;
485             }
486             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
487             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
488             ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
489             ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
490             ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
491             ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
492             ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
493             ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
494             d += linesize;
495         }
496         break;
497     }
498 }
499
500 static void text_console_resize(TextConsole *s)
501 {
502     TextCell *cells, *c, *c1;
503     int w1, x, y, last_width;
504
505     last_width = s->width;
506     s->width = s->g_width / FONT_WIDTH;
507     s->height = s->g_height / FONT_HEIGHT;
508
509     w1 = last_width;
510     if (s->width < w1)
511         w1 = s->width;
512
513     cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
514     for(y = 0; y < s->total_height; y++) {
515         c = &cells[y * s->width];
516         if (w1 > 0) {
517             c1 = &s->cells[y * last_width];
518             for(x = 0; x < w1; x++) {
519                 *c++ = *c1++;
520             }
521         }
522         for(x = w1; x < s->width; x++) {
523             c->ch = ' ';
524             c->t_attrib = s->t_attrib_default;
525             c++;
526         }
527     }
528     qemu_free(s->cells);
529     s->cells = cells;
530 }
531
532 static inline void text_update_xy(TextConsole *s, int x, int y)
533 {
534     s->text_x[0] = MIN(s->text_x[0], x);
535     s->text_x[1] = MAX(s->text_x[1], x);
536     s->text_y[0] = MIN(s->text_y[0], y);
537     s->text_y[1] = MAX(s->text_y[1], y);
538 }
539
540 static void update_xy(TextConsole *s, int x, int y)
541 {
542     TextCell *c;
543     int y1, y2;
544
545     if (s == active_console) {
546         if (!ds_get_bits_per_pixel(s->ds)) {
547             text_update_xy(s, x, y);
548             return;
549         }
550
551         y1 = (s->y_base + y) % s->total_height;
552         y2 = y1 - s->y_displayed;
553         if (y2 < 0)
554             y2 += s->total_height;
555         if (y2 < s->height) {
556             c = &s->cells[y1 * s->width + x];
557             vga_putcharxy(s->ds, x, y2, c->ch,
558                           &(c->t_attrib));
559             dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
560                        FONT_WIDTH, FONT_HEIGHT);
561         }
562     }
563 }
564
565 static void console_show_cursor(TextConsole *s, int show)
566 {
567     TextCell *c;
568     int y, y1;
569
570     if (s == active_console) {
571         int x = s->x;
572
573         if (!ds_get_bits_per_pixel(s->ds)) {
574             s->cursor_invalidate = 1;
575             return;
576         }
577
578         if (x >= s->width) {
579             x = s->width - 1;
580         }
581         y1 = (s->y_base + s->y) % s->total_height;
582         y = y1 - s->y_displayed;
583         if (y < 0)
584             y += s->total_height;
585         if (y < s->height) {
586             c = &s->cells[y1 * s->width + x];
587             if (show) {
588                 TextAttributes t_attrib = s->t_attrib_default;
589                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
590                 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
591             } else {
592                 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
593             }
594             dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
595                        FONT_WIDTH, FONT_HEIGHT);
596         }
597     }
598 }
599
600 static void console_refresh(TextConsole *s)
601 {
602     TextCell *c;
603     int x, y, y1;
604
605     if (s != active_console)
606         return;
607     if (!ds_get_bits_per_pixel(s->ds)) {
608         s->text_x[0] = 0;
609         s->text_y[0] = 0;
610         s->text_x[1] = s->width - 1;
611         s->text_y[1] = s->height - 1;
612         s->cursor_invalidate = 1;
613         return;
614     }
615
616     vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
617                   color_table[0][COLOR_BLACK]);
618     y1 = s->y_displayed;
619     for(y = 0; y < s->height; y++) {
620         c = s->cells + y1 * s->width;
621         for(x = 0; x < s->width; x++) {
622             vga_putcharxy(s->ds, x, y, c->ch,
623                           &(c->t_attrib));
624             c++;
625         }
626         if (++y1 == s->total_height)
627             y1 = 0;
628     }
629     dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
630     console_show_cursor(s, 1);
631 }
632
633 static void console_scroll(int ydelta)
634 {
635     TextConsole *s;
636     int i, y1;
637
638     s = active_console;
639     if (!s || (s->console_type == GRAPHIC_CONSOLE))
640         return;
641
642     if (ydelta > 0) {
643         for(i = 0; i < ydelta; i++) {
644             if (s->y_displayed == s->y_base)
645                 break;
646             if (++s->y_displayed == s->total_height)
647                 s->y_displayed = 0;
648         }
649     } else {
650         ydelta = -ydelta;
651         i = s->backscroll_height;
652         if (i > s->total_height - s->height)
653             i = s->total_height - s->height;
654         y1 = s->y_base - i;
655         if (y1 < 0)
656             y1 += s->total_height;
657         for(i = 0; i < ydelta; i++) {
658             if (s->y_displayed == y1)
659                 break;
660             if (--s->y_displayed < 0)
661                 s->y_displayed = s->total_height - 1;
662         }
663     }
664     console_refresh(s);
665 }
666
667 static void console_put_lf(TextConsole *s)
668 {
669     TextCell *c;
670     int x, y1;
671
672     s->y++;
673     if (s->y >= s->height) {
674         s->y = s->height - 1;
675
676         if (s->y_displayed == s->y_base) {
677             if (++s->y_displayed == s->total_height)
678                 s->y_displayed = 0;
679         }
680         if (++s->y_base == s->total_height)
681             s->y_base = 0;
682         if (s->backscroll_height < s->total_height)
683             s->backscroll_height++;
684         y1 = (s->y_base + s->height - 1) % s->total_height;
685         c = &s->cells[y1 * s->width];
686         for(x = 0; x < s->width; x++) {
687             c->ch = ' ';
688             c->t_attrib = s->t_attrib_default;
689             c++;
690         }
691         if (s == active_console && s->y_displayed == s->y_base) {
692             if (!ds_get_bits_per_pixel(s->ds)) {
693                 s->text_x[0] = 0;
694                 s->text_y[0] = 0;
695                 s->text_x[1] = s->width - 1;
696                 s->text_y[1] = s->height - 1;
697                 return;
698             }
699
700             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
701                        s->width * FONT_WIDTH,
702                        (s->height - 1) * FONT_HEIGHT);
703             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
704                           s->width * FONT_WIDTH, FONT_HEIGHT,
705                           color_table[0][s->t_attrib_default.bgcol]);
706             dpy_update(s->ds, 0, 0,
707                        s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
708         }
709     }
710 }
711
712 /* Set console attributes depending on the current escape codes.
713  * NOTE: I know this code is not very efficient (checking every color for it
714  * self) but it is more readable and better maintainable.
715  */
716 static void console_handle_escape(TextConsole *s)
717 {
718     int i;
719
720     for (i=0; i<s->nb_esc_params; i++) {
721         switch (s->esc_params[i]) {
722             case 0: /* reset all console attributes to default */
723                 s->t_attrib = s->t_attrib_default;
724                 break;
725             case 1:
726                 s->t_attrib.bold = 1;
727                 break;
728             case 4:
729                 s->t_attrib.uline = 1;
730                 break;
731             case 5:
732                 s->t_attrib.blink = 1;
733                 break;
734             case 7:
735                 s->t_attrib.invers = 1;
736                 break;
737             case 8:
738                 s->t_attrib.unvisible = 1;
739                 break;
740             case 22:
741                 s->t_attrib.bold = 0;
742                 break;
743             case 24:
744                 s->t_attrib.uline = 0;
745                 break;
746             case 25:
747                 s->t_attrib.blink = 0;
748                 break;
749             case 27:
750                 s->t_attrib.invers = 0;
751                 break;
752             case 28:
753                 s->t_attrib.unvisible = 0;
754                 break;
755             /* set foreground color */
756             case 30:
757                 s->t_attrib.fgcol=COLOR_BLACK;
758                 break;
759             case 31:
760                 s->t_attrib.fgcol=COLOR_RED;
761                 break;
762             case 32:
763                 s->t_attrib.fgcol=COLOR_GREEN;
764                 break;
765             case 33:
766                 s->t_attrib.fgcol=COLOR_YELLOW;
767                 break;
768             case 34:
769                 s->t_attrib.fgcol=COLOR_BLUE;
770                 break;
771             case 35:
772                 s->t_attrib.fgcol=COLOR_MAGENTA;
773                 break;
774             case 36:
775                 s->t_attrib.fgcol=COLOR_CYAN;
776                 break;
777             case 37:
778                 s->t_attrib.fgcol=COLOR_WHITE;
779                 break;
780             /* set background color */
781             case 40:
782                 s->t_attrib.bgcol=COLOR_BLACK;
783                 break;
784             case 41:
785                 s->t_attrib.bgcol=COLOR_RED;
786                 break;
787             case 42:
788                 s->t_attrib.bgcol=COLOR_GREEN;
789                 break;
790             case 43:
791                 s->t_attrib.bgcol=COLOR_YELLOW;
792                 break;
793             case 44:
794                 s->t_attrib.bgcol=COLOR_BLUE;
795                 break;
796             case 45:
797                 s->t_attrib.bgcol=COLOR_MAGENTA;
798                 break;
799             case 46:
800                 s->t_attrib.bgcol=COLOR_CYAN;
801                 break;
802             case 47:
803                 s->t_attrib.bgcol=COLOR_WHITE;
804                 break;
805         }
806     }
807 }
808
809 static void console_clear_xy(TextConsole *s, int x, int y)
810 {
811     int y1 = (s->y_base + y) % s->total_height;
812     TextCell *c = &s->cells[y1 * s->width + x];
813     c->ch = ' ';
814     c->t_attrib = s->t_attrib_default;
815     c++;
816     update_xy(s, x, y);
817 }
818
819 static void console_putchar(TextConsole *s, int ch)
820 {
821     TextCell *c;
822     int y1, i;
823     int x, y;
824
825     switch(s->state) {
826     case TTY_STATE_NORM:
827         switch(ch) {
828         case '\r':  /* carriage return */
829             s->x = 0;
830             break;
831         case '\n':  /* newline */
832             console_put_lf(s);
833             break;
834         case '\b':  /* backspace */
835             if (s->x > 0)
836                 s->x--;
837             break;
838         case '\t':  /* tabspace */
839             if (s->x + (8 - (s->x % 8)) > s->width) {
840                 s->x = 0;
841                 console_put_lf(s);
842             } else {
843                 s->x = s->x + (8 - (s->x % 8));
844             }
845             break;
846         case '\a':  /* alert aka. bell */
847             /* TODO: has to be implemented */
848             break;
849         case 14:
850             /* SI (shift in), character set 0 (ignored) */
851             break;
852         case 15:
853             /* SO (shift out), character set 1 (ignored) */
854             break;
855         case 27:    /* esc (introducing an escape sequence) */
856             s->state = TTY_STATE_ESC;
857             break;
858         default:
859             if (s->x >= s->width) {
860                 /* line wrap */
861                 s->x = 0;
862                 console_put_lf(s);
863             }
864             y1 = (s->y_base + s->y) % s->total_height;
865             c = &s->cells[y1 * s->width + s->x];
866             c->ch = ch;
867             c->t_attrib = s->t_attrib;
868             update_xy(s, s->x, s->y);
869             s->x++;
870             break;
871         }
872         break;
873     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
874         if (ch == '[') {
875             for(i=0;i<MAX_ESC_PARAMS;i++)
876                 s->esc_params[i] = 0;
877             s->nb_esc_params = 0;
878             s->state = TTY_STATE_CSI;
879         } else {
880             s->state = TTY_STATE_NORM;
881         }
882         break;
883     case TTY_STATE_CSI: /* handle escape sequence parameters */
884         if (ch >= '0' && ch <= '9') {
885             if (s->nb_esc_params < MAX_ESC_PARAMS) {
886                 s->esc_params[s->nb_esc_params] =
887                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
888             }
889         } else {
890             s->nb_esc_params++;
891             if (ch == ';')
892                 break;
893 #ifdef DEBUG_CONSOLE
894             fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
895                     s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
896 #endif
897             s->state = TTY_STATE_NORM;
898             switch(ch) {
899             case 'A':
900                 /* move cursor up */
901                 if (s->esc_params[0] == 0) {
902                     s->esc_params[0] = 1;
903                 }
904                 s->y -= s->esc_params[0];
905                 if (s->y < 0) {
906                     s->y = 0;
907                 }
908                 break;
909             case 'B':
910                 /* move cursor down */
911                 if (s->esc_params[0] == 0) {
912                     s->esc_params[0] = 1;
913                 }
914                 s->y += s->esc_params[0];
915                 if (s->y >= s->height) {
916                     s->y = s->height - 1;
917                 }
918                 break;
919             case 'C':
920                 /* move cursor right */
921                 if (s->esc_params[0] == 0) {
922                     s->esc_params[0] = 1;
923                 }
924                 s->x += s->esc_params[0];
925                 if (s->x >= s->width) {
926                     s->x = s->width - 1;
927                 }
928                 break;
929             case 'D':
930                 /* move cursor left */
931                 if (s->esc_params[0] == 0) {
932                     s->esc_params[0] = 1;
933                 }
934                 s->x -= s->esc_params[0];
935                 if (s->x < 0) {
936                     s->x = 0;
937                 }
938                 break;
939             case 'G':
940                 /* move cursor to column */
941                 s->x = s->esc_params[0] - 1;
942                 if (s->x < 0) {
943                     s->x = 0;
944                 }
945                 break;
946             case 'f':
947             case 'H':
948                 /* move cursor to row, column */
949                 s->x = s->esc_params[1] - 1;
950                 if (s->x < 0) {
951                     s->x = 0;
952                 }
953                 s->y = s->esc_params[0] - 1;
954                 if (s->y < 0) {
955                     s->y = 0;
956                 }
957                 break;
958             case 'J':
959                 switch (s->esc_params[0]) {
960                 case 0:
961                     /* clear to end of screen */
962                     for (y = s->y; y < s->height; y++) {
963                         for (x = 0; x < s->width; x++) {
964                             if (y == s->y && x < s->x) {
965                                 continue;
966                             }
967                             console_clear_xy(s, x, y);
968                         }
969                     }
970                     break;
971                 case 1:
972                     /* clear from beginning of screen */
973                     for (y = 0; y <= s->y; y++) {
974                         for (x = 0; x < s->width; x++) {
975                             if (y == s->y && x > s->x) {
976                                 break;
977                             }
978                             console_clear_xy(s, x, y);
979                         }
980                     }
981                     break;
982                 case 2:
983                     /* clear entire screen */
984                     for (y = 0; y <= s->height; y++) {
985                         for (x = 0; x < s->width; x++) {
986                             console_clear_xy(s, x, y);
987                         }
988                     }
989                 break;
990                 }
991             case 'K':
992                 switch (s->esc_params[0]) {
993                 case 0:
994                 /* clear to eol */
995                 for(x = s->x; x < s->width; x++) {
996                         console_clear_xy(s, x, s->y);
997                 }
998                 break;
999                 case 1:
1000                     /* clear from beginning of line */
1001                     for (x = 0; x <= s->x; x++) {
1002                         console_clear_xy(s, x, s->y);
1003                     }
1004                     break;
1005                 case 2:
1006                     /* clear entire line */
1007                     for(x = 0; x < s->width; x++) {
1008                         console_clear_xy(s, x, s->y);
1009                     }
1010                 break;
1011             }
1012                 break;
1013             case 'm':
1014             console_handle_escape(s);
1015             break;
1016             case 'n':
1017                 /* report cursor position */
1018                 /* TODO: send ESC[row;colR */
1019                 break;
1020             case 's':
1021                 /* save cursor position */
1022                 s->x_saved = s->x;
1023                 s->y_saved = s->y;
1024                 break;
1025             case 'u':
1026                 /* restore cursor position */
1027                 s->x = s->x_saved;
1028                 s->y = s->y_saved;
1029                 break;
1030             default:
1031 #ifdef DEBUG_CONSOLE
1032                 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1033 #endif
1034                 break;
1035             }
1036             break;
1037         }
1038     }
1039 }
1040
1041 void console_select(unsigned int index)
1042 {
1043     TextConsole *s;
1044
1045     if (index >= MAX_CONSOLES)
1046         return;
1047     active_console->g_width = ds_get_width(active_console->ds);
1048     active_console->g_height = ds_get_height(active_console->ds);
1049     s = consoles[index];
1050     if (s) {
1051         DisplayState *ds = s->ds;
1052         active_console = s;
1053         ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,
1054                                                 s->g_height, 32, 4 * s->g_width);
1055         dpy_resize(s->ds);
1056         vga_hw_invalidate();
1057     }
1058 }
1059
1060 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1061 {
1062     TextConsole *s = chr->opaque;
1063     int i;
1064
1065     console_show_cursor(s, 0);
1066     for(i = 0; i < len; i++) {
1067         console_putchar(s, buf[i]);
1068     }
1069     console_show_cursor(s, 1);
1070     return len;
1071 }
1072
1073 static void console_send_event(CharDriverState *chr, int event)
1074 {
1075     TextConsole *s = chr->opaque;
1076     int i;
1077
1078     if (event == CHR_EVENT_FOCUS) {
1079         for(i = 0; i < nb_consoles; i++) {
1080             if (consoles[i] == s) {
1081                 console_select(i);
1082                 break;
1083             }
1084         }
1085     }
1086 }
1087
1088 static void kbd_send_chars(void *opaque)
1089 {
1090     TextConsole *s = opaque;
1091     int len;
1092     uint8_t buf[16];
1093
1094     len = qemu_chr_can_read(s->chr);
1095     if (len > s->out_fifo.count)
1096         len = s->out_fifo.count;
1097     if (len > 0) {
1098         if (len > sizeof(buf))
1099             len = sizeof(buf);
1100         qemu_fifo_read(&s->out_fifo, buf, len);
1101         qemu_chr_read(s->chr, buf, len);
1102     }
1103     /* characters are pending: we send them a bit later (XXX:
1104        horrible, should change char device API) */
1105     if (s->out_fifo.count > 0) {
1106         qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1107     }
1108 }
1109
1110 /* called when an ascii key is pressed */
1111 void kbd_put_keysym(int keysym)
1112 {
1113     TextConsole *s;
1114     uint8_t buf[16], *q;
1115     int c;
1116
1117     s = active_console;
1118     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1119         return;
1120
1121     switch(keysym) {
1122     case QEMU_KEY_CTRL_UP:
1123         console_scroll(-1);
1124         break;
1125     case QEMU_KEY_CTRL_DOWN:
1126         console_scroll(1);
1127         break;
1128     case QEMU_KEY_CTRL_PAGEUP:
1129         console_scroll(-10);
1130         break;
1131     case QEMU_KEY_CTRL_PAGEDOWN:
1132         console_scroll(10);
1133         break;
1134     default:
1135         /* convert the QEMU keysym to VT100 key string */
1136         q = buf;
1137         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1138             *q++ = '\033';
1139             *q++ = '[';
1140             c = keysym - 0xe100;
1141             if (c >= 10)
1142                 *q++ = '0' + (c / 10);
1143             *q++ = '0' + (c % 10);
1144             *q++ = '~';
1145         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1146             *q++ = '\033';
1147             *q++ = '[';
1148             *q++ = keysym & 0xff;
1149         } else {
1150                 *q++ = keysym;
1151         }
1152         if (s->chr->chr_read) {
1153             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1154             kbd_send_chars(s);
1155         }
1156         break;
1157     }
1158 }
1159
1160 static void text_console_invalidate(void *opaque)
1161 {
1162     TextConsole *s = (TextConsole *) opaque;
1163     console_refresh(s);
1164 }
1165
1166 static void text_console_update(void *opaque, console_ch_t *chardata)
1167 {
1168     TextConsole *s = (TextConsole *) opaque;
1169     int i, j, src;
1170
1171     if (s->text_x[0] <= s->text_x[1]) {
1172         src = (s->y_base + s->text_y[0]) * s->width;
1173         chardata += s->text_y[0] * s->width;
1174         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1175             for (j = 0; j < s->width; j ++, src ++)
1176                 console_write_ch(chardata ++, s->cells[src].ch |
1177                                 (s->cells[src].t_attrib.fgcol << 12) |
1178                                 (s->cells[src].t_attrib.bgcol << 8) |
1179                                 (s->cells[src].t_attrib.bold << 21));
1180         dpy_update(s->ds, s->text_x[0], s->text_y[0],
1181                    s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1182         s->text_x[0] = s->width;
1183         s->text_y[0] = s->height;
1184         s->text_x[1] = 0;
1185         s->text_y[1] = 0;
1186     }
1187     if (s->cursor_invalidate) {
1188         dpy_cursor(s->ds, s->x, s->y);
1189         s->cursor_invalidate = 0;
1190     }
1191 }
1192
1193 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1194 {
1195     TextConsole *s;
1196     int i;
1197
1198     if (nb_consoles >= MAX_CONSOLES)
1199         return NULL;
1200     s = qemu_mallocz(sizeof(TextConsole));
1201     if (!s) {
1202         return NULL;
1203     }
1204     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1205         (console_type == GRAPHIC_CONSOLE))) {
1206         active_console = s;
1207     }
1208     s->ds = ds;
1209     s->console_type = console_type;
1210     if (console_type != GRAPHIC_CONSOLE) {
1211         consoles[nb_consoles++] = s;
1212     } else {
1213         /* HACK: Put graphical consoles before text consoles.  */
1214         for (i = nb_consoles; i > 0; i--) {
1215             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1216                 break;
1217             consoles[i] = consoles[i - 1];
1218         }
1219         consoles[i] = s;
1220     }
1221     return s;
1222 }
1223
1224 TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1225                                   vga_hw_invalidate_ptr invalidate,
1226                                   vga_hw_screen_dump_ptr screen_dump,
1227                                   vga_hw_text_update_ptr text_update,
1228                                   void *opaque)
1229 {
1230     TextConsole *s;
1231
1232     s = new_console(ds, GRAPHIC_CONSOLE);
1233     if (!s)
1234       return NULL;
1235     s->hw_update = update;
1236     s->hw_invalidate = invalidate;
1237     s->hw_screen_dump = screen_dump;
1238     s->hw_text_update = text_update;
1239     s->hw = opaque;
1240     return s;
1241 }
1242
1243 int is_graphic_console(void)
1244 {
1245     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1246 }
1247
1248 int is_fixedsize_console(void)
1249 {
1250     return active_console && active_console->console_type != TEXT_CONSOLE;
1251 }
1252
1253 void console_color_init(DisplayState *ds)
1254 {
1255     int i, j;
1256     for (j = 0; j < 2; j++) {
1257         for (i = 0; i < 8; i++) {
1258             color_table[j][i] = col_expand(ds, 
1259                    vga_get_color(ds, color_table_rgb[j][i]));
1260         }
1261     }
1262 }
1263
1264 CharDriverState *text_console_init(DisplayState *ds, const char *p)
1265 {
1266     CharDriverState *chr;
1267     TextConsole *s;
1268     unsigned width;
1269     unsigned height;
1270     static int color_inited;
1271
1272     chr = qemu_mallocz(sizeof(CharDriverState));
1273     if (!chr)
1274         return NULL;
1275     s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1276     if (!s) {
1277         free(chr);
1278         return NULL;
1279     }
1280     chr->opaque = s;
1281     chr->chr_write = console_puts;
1282     chr->chr_send_event = console_send_event;
1283
1284     s->chr = chr;
1285     s->out_fifo.buf = s->out_fifo_buf;
1286     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1287     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1288
1289     if (!color_inited) {
1290         color_inited = 1;
1291         console_color_init(s->ds);
1292     }
1293     s->y_displayed = 0;
1294     s->y_base = 0;
1295     s->total_height = DEFAULT_BACKSCROLL;
1296     s->x = 0;
1297     s->y = 0;
1298     width = ds_get_width(s->ds);
1299     height = ds_get_height(s->ds);
1300     if (p != 0) {
1301         width = strtoul(p, (char **)&p, 10);
1302         if (*p == 'C') {
1303             p++;
1304             width *= FONT_WIDTH;
1305         }
1306         if (*p == 'x') {
1307             p++;
1308             height = strtoul(p, (char **)&p, 10);
1309             if (*p == 'C') {
1310                 p++;
1311                 height *= FONT_HEIGHT;
1312             }
1313         }
1314     }
1315     s->g_width = width;
1316     s->g_height = height;
1317
1318     s->hw_invalidate = text_console_invalidate;
1319     s->hw_text_update = text_console_update;
1320     s->hw = s;
1321
1322     /* Set text attribute defaults */
1323     s->t_attrib_default.bold = 0;
1324     s->t_attrib_default.uline = 0;
1325     s->t_attrib_default.blink = 0;
1326     s->t_attrib_default.invers = 0;
1327     s->t_attrib_default.unvisible = 0;
1328     s->t_attrib_default.fgcol = COLOR_WHITE;
1329     s->t_attrib_default.bgcol = COLOR_BLACK;
1330
1331     /* set current text attributes to default */
1332     s->t_attrib = s->t_attrib_default;
1333     text_console_resize(s);
1334
1335     qemu_chr_reset(chr);
1336
1337     return chr;
1338 }
1339
1340 void qemu_console_resize(QEMUConsole *console, int width, int height)
1341 {
1342     console->g_width = width;
1343     console->g_height = height;
1344     if (active_console == console) {
1345         DisplayState *ds = console->ds;
1346         ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
1347         dpy_resize(console->ds);
1348     }
1349 }
1350
1351 void qemu_console_copy(QEMUConsole *console, int src_x, int src_y,
1352                 int dst_x, int dst_y, int w, int h)
1353 {
1354     if (active_console == console) {
1355             dpy_copy(console->ds, src_x, src_y, dst_x, dst_y, w, h);
1356     }
1357 }
1358
1359 static PixelFormat qemu_default_pixelformat(int bpp)
1360 {
1361     PixelFormat pf;
1362
1363     memset(&pf, 0x00, sizeof(PixelFormat));
1364
1365     pf.bits_per_pixel = bpp;
1366     pf.bytes_per_pixel = bpp / 8;
1367     pf.depth = bpp == 32 ? 24 : bpp;
1368
1369     switch (bpp) {
1370         case 8:
1371             pf.rmask = 0x000000E0;
1372             pf.gmask = 0x0000001C;
1373             pf.bmask = 0x00000003;
1374             pf.rmax = 7;
1375             pf.gmax = 7;
1376             pf.bmax = 3;
1377             pf.rshift = 5;
1378             pf.gshift = 2;
1379             pf.bshift = 0;
1380             break;
1381         case 16:
1382             pf.rmask = 0x0000F800;
1383             pf.gmask = 0x000007E0;
1384             pf.bmask = 0x0000001F;
1385             pf.rmax = 31;
1386             pf.gmax = 63;
1387             pf.bmax = 31;
1388             pf.rshift = 11;
1389             pf.gshift = 5;
1390             pf.bshift = 0;
1391             break;
1392         case 24:
1393         case 32:
1394             pf.rmask = 0x00FF0000;
1395             pf.gmask = 0x0000FF00;
1396             pf.bmask = 0x000000FF;
1397             pf.rmax = 255;
1398             pf.gmax = 255;
1399             pf.bmax = 255;
1400             pf.rshift = 16;
1401             pf.gshift = 8;
1402             pf.bshift = 0;
1403             break;
1404         default:
1405             break;
1406     }
1407     return pf;
1408 }
1409
1410 DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
1411 {
1412     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1413     if (surface == NULL) {
1414         fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1415         exit(1);
1416     }
1417
1418     surface->width = width;
1419     surface->height = height;
1420     surface->linesize = linesize;
1421     surface->pf = qemu_default_pixelformat(bpp);
1422 #ifdef WORDS_BIGENDIAN
1423     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1424 #else
1425     surface->flags = QEMU_ALLOCATED_FLAG;
1426 #endif
1427     surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1428     if (surface->data == NULL) {
1429         fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1430         exit(1);
1431     }
1432
1433     return surface;
1434 }
1435
1436 DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
1437                                           int width, int height, int bpp, int linesize)
1438 {
1439     surface->width = width;
1440     surface->height = height;
1441     surface->linesize = linesize;
1442     surface->pf = qemu_default_pixelformat(bpp);
1443     if (surface->flags & QEMU_ALLOCATED_FLAG)
1444         surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1445     else
1446         surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1447     if (surface->data == NULL) {
1448         fprintf(stderr, "qemu_resize_displaysurface: malloc failed\n");
1449         exit(1);
1450     }
1451 #ifdef WORDS_BIGENDIAN
1452     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1453 #else
1454     surface->flags = QEMU_ALLOCATED_FLAG;
1455 #endif
1456
1457     return surface;
1458 }
1459
1460 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1461                                               int linesize, uint8_t *data)
1462 {
1463     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1464     if (surface == NULL) {
1465         fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n");
1466         exit(1);
1467     }
1468
1469     surface->width = width;
1470     surface->height = height;
1471     surface->linesize = linesize;
1472     surface->pf = qemu_default_pixelformat(bpp);
1473 #ifdef WORDS_BIGENDIAN
1474     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1475 #endif
1476     surface->data = data;
1477
1478     return surface;
1479 }
1480
1481 void qemu_free_displaysurface(DisplaySurface *surface)
1482 {
1483     if (surface == NULL)
1484         return;
1485     if (surface->flags & QEMU_ALLOCATED_FLAG)
1486         qemu_free(surface->data);
1487     qemu_free(surface);
1488 }