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