blob: 9bbef593b94f849b9cd52c8be88b481e6cdc86a6 [file] [log] [blame]
bellarde7f0ad52004-07-14 17:28:59 +00001/*
2 * QEMU graphical console
ths5fafdf22007-09-16 21:08:06 +00003 *
bellarde7f0ad52004-07-14 17:28:59 +00004 * Copyright (c) 2004 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde7f0ad52004-07-14 17:28:59 +00006 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "qemu-common.h"
25#include "console.h"
26#include "qemu-timer.h"
bellarde7f0ad52004-07-14 17:28:59 +000027
pbrook6d6f7c22006-03-11 15:35:30 +000028//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000029#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
31
bellard26489842006-06-25 17:37:36 +000032#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)
bellarde7f0ad52004-07-14 17:28:59 +000034
pbrook6d6f7c22006-03-11 15:35:30 +000035typedef 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
bellarde7f0ad52004-07-14 17:28:59 +000045typedef struct TextCell {
46 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000047 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000048} TextCell;
49
50#define MAX_ESC_PARAMS 3
51
52enum TTYState {
53 TTY_STATE_NORM,
54 TTY_STATE_ESC,
55 TTY_STATE_CSI,
56};
57
bellarde15d7372006-06-25 16:26:29 +000058typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62} QEMUFIFO;
63
pbrook9596ebb2007-11-18 01:44:38 +000064static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000065{
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
pbrook9596ebb2007-11-18 01:44:38 +000087static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000088{
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
thsaf3a9032007-07-11 23:14:59 +0000109typedef enum {
110 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500113} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000114
pbrook95219892006-04-09 01:06:34 +0000115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
bellarde7f0ad52004-07-14 17:28:59 +0000117struct TextConsole {
Anthony Liguoric227f092009-10-01 16:12:16 -0500118 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000119 DisplayState *ds;
pbrook95219892006-04-09 01:06:34 +0000120 /* 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;
balrog4d3b6f62008-02-10 16:33:14 +0000124 vga_hw_text_update_ptr hw_text_update;
pbrook95219892006-04-09 01:06:34 +0000125 void *hw;
126
bellarde7f0ad52004-07-14 17:28:59 +0000127 int g_width, g_height;
128 int width;
129 int height;
130 int total_height;
131 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000132 int x, y;
thsadb47962007-01-16 23:02:36 +0000133 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000134 int y_displayed;
135 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000136 TextAttributes t_attrib_default; /* default text attributes */
137 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000138 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000139 int text_x[2], text_y[2], cursor_invalidate;
bellarde7f0ad52004-07-14 17:28:59 +0000140
pbrook14778c22009-01-21 03:02:52 +0000141 int update_x0;
142 int update_y0;
143 int update_x1;
144 int update_y1;
145
bellarde7f0ad52004-07-14 17:28:59 +0000146 enum TTYState state;
147 int esc_params[MAX_ESC_PARAMS];
148 int nb_esc_params;
149
pbrooke5b0bc42007-01-27 23:46:43 +0000150 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000151 /* fifo for key pressed */
152 QEMUFIFO out_fifo;
153 uint8_t out_fifo_buf[16];
154 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000155};
156
157static TextConsole *active_console;
158static TextConsole *consoles[MAX_CONSOLES];
159static int nb_consoles = 0;
160
pbrook95219892006-04-09 01:06:34 +0000161void vga_hw_update(void)
162{
thsadb47962007-01-16 23:02:36 +0000163 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000164 active_console->hw_update(active_console->hw);
165}
166
167void vga_hw_invalidate(void)
168{
169 if (active_console->hw_invalidate)
170 active_console->hw_invalidate(active_console->hw);
171}
172
173void vga_hw_screen_dump(const char *filename)
174{
balrog8571c052008-07-19 13:04:26 +0000175 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,
aurel327b455222008-09-02 00:09:16 +0000180 so always dump the first one. */
pbrook95219892006-04-09 01:06:34 +0000181 if (consoles[0]->hw_screen_dump)
182 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
balrog8571c052008-07-19 13:04:26 +0000183 active_console = previous_active_console;
pbrook95219892006-04-09 01:06:34 +0000184}
185
Anthony Liguoric227f092009-10-01 16:12:16 -0500186void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000187{
188 if (active_console && active_console->hw_text_update)
189 active_console->hw_text_update(active_console->hw, chardata);
190}
191
bellarde7f0ad52004-07-14 17:28:59 +0000192/* convert a RGBA color to a color index usable in graphic primitives */
193static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
194{
195 unsigned int r, g, b, color;
196
aliguori0e1f5a02008-11-24 19:29:13 +0000197 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000198#if 0
199 case 8:
200 r = (rgba >> 16) & 0xff;
201 g = (rgba >> 8) & 0xff;
202 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000203 color = (rgb_to_index[r] * 6 * 6) +
204 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000205 (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
ths5fafdf22007-09-16 21:08:06 +0000228static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000229 int posx, int posy, int width, int height, uint32_t color)
230{
231 uint8_t *d, *d1;
232 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000233
aliguori0e1f5a02008-11-24 19:29:13 +0000234 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
235 d1 = ds_get_data(ds) +
236 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000237 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 }
aliguori0e1f5a02008-11-24 19:29:13 +0000259 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000260 }
261}
262
263/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
264static 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
aliguori0e1f5a02008-11-24 19:29:13 +0000270 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000271 wb = w * bpp;
272 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000273 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;
bellarde7f0ad52004-07-14 17:28:59 +0000277 for (y = 0; y < h; y++) {
278 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000279 d += ds_get_linesize(ds);
280 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000281 }
282 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000283 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;
bellarde7f0ad52004-07-14 17:28:59 +0000287 for (y = 0; y < h; y++) {
288 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000289 d -= ds_get_linesize(ds);
290 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000291 }
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
Juan Quintelae2542fe2009-07-27 16:13:06 +0200310#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000311#define PAT(x) x
312#else
313#define PAT(x) cbswap_32(x)
314#endif
315
316static 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
335static const uint32_t dmask4[4] = {
336 PAT(0x00000000),
337 PAT(0x0000ffff),
338 PAT(0xffff0000),
339 PAT(0xffffffff),
340};
341
pbrook6d6f7c22006-03-11 15:35:30 +0000342static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000343
pbrook6d6f7c22006-03-11 15:35:30 +0000344enum 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
355static const uint32_t color_table_rgb[2][8] = {
356 { /* dark */
bellard26489842006-06-25 17:37:36 +0000357 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 */
pbrook6d6f7c22006-03-11 15:35:30 +0000365 },
366 { /* bright */
bellard26489842006-06-25 17:37:36 +0000367 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 */
pbrook6d6f7c22006-03-11 15:35:30 +0000375 }
bellarde7f0ad52004-07-14 17:28:59 +0000376};
377
378static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
379{
aliguori0e1f5a02008-11-24 19:29:13 +0000380 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000381 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}
pbrook6d6f7c22006-03-11 15:35:30 +0000395#ifdef DEBUG_CONSOLE
396static 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
bellarde7f0ad52004-07-14 17:28:59 +0000427
ths5fafdf22007-09-16 21:08:06 +0000428static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000429 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000430{
431 uint8_t *d;
432 const uint8_t *font_ptr;
433 unsigned int font_data, linesize, xorcol, bpp;
434 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000435 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 }
bellarde7f0ad52004-07-14 17:28:59 +0000449
aliguori0e1f5a02008-11-24 19:29:13 +0000450 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);
bellarde7f0ad52004-07-14 17:28:59 +0000454 font_ptr = vgafont16 + FONT_HEIGHT * ch;
455 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000456 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000457 case 8:
458 for(i = 0; i < FONT_HEIGHT; i++) {
459 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000460 if (t_attrib->uline
461 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
462 font_data = 0xFFFF;
463 }
bellarde7f0ad52004-07-14 17:28:59 +0000464 ((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++;
pbrook6d6f7c22006-03-11 15:35:30 +0000473 if (t_attrib->uline
474 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
475 font_data = 0xFFFF;
476 }
bellarde7f0ad52004-07-14 17:28:59 +0000477 ((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++;
pbrook6d6f7c22006-03-11 15:35:30 +0000487 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
488 font_data = 0xFFFF;
489 }
bellarde7f0ad52004-07-14 17:28:59 +0000490 ((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
504static 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 = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000528 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000529 c++;
530 }
531 }
balroga528b802007-10-30 22:38:53 +0000532 qemu_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000533 s->cells = cells;
534}
535
balrog4d3b6f62008-02-10 16:33:14 +0000536static 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
pbrook14778c22009-01-21 03:02:52 +0000544static 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
bellarde7f0ad52004-07-14 17:28:59 +0000556static void update_xy(TextConsole *s, int x, int y)
557{
558 TextCell *c;
559 int y1, y2;
560
561 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000562 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000563 text_update_xy(s, x, y);
564 return;
565 }
566
bellarde7f0ad52004-07-14 17:28:59 +0000567 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];
ths5fafdf22007-09-16 21:08:06 +0000573 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000574 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000575 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000576 }
577 }
578}
579
580static void console_show_cursor(TextConsole *s, int show)
581{
582 TextCell *c;
583 int y, y1;
584
585 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000586 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000587
aliguori0e1f5a02008-11-24 19:29:13 +0000588 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000589 s->cursor_invalidate = 1;
590 return;
591 }
592
thsed8276a2007-02-10 22:37:56 +0000593 if (x >= s->width) {
594 x = s->width - 1;
595 }
bellarde7f0ad52004-07-14 17:28:59 +0000596 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) {
thsed8276a2007-02-10 22:37:56 +0000601 c = &s->cells[y1 * s->width + x];
bellarde7f0ad52004-07-14 17:28:59 +0000602 if (show) {
pbrook6d6f7c22006-03-11 15:35:30 +0000603 TextAttributes t_attrib = s->t_attrib_default;
604 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000605 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000606 } else {
thsed8276a2007-02-10 22:37:56 +0000607 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000608 }
pbrook14778c22009-01-21 03:02:52 +0000609 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000610 }
611 }
612}
613
614static void console_refresh(TextConsole *s)
615{
616 TextCell *c;
617 int x, y, y1;
618
ths5fafdf22007-09-16 21:08:06 +0000619 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000620 return;
aliguori0e1f5a02008-11-24 19:29:13 +0000621 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000622 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 }
bellarde7f0ad52004-07-14 17:28:59 +0000629
aliguori0e1f5a02008-11-24 19:29:13 +0000630 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
pbrook6d6f7c22006-03-11 15:35:30 +0000631 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000632 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++) {
ths5fafdf22007-09-16 21:08:06 +0000636 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000637 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000638 c++;
639 }
640 if (++y1 == s->total_height)
641 y1 = 0;
642 }
bellarde7f0ad52004-07-14 17:28:59 +0000643 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +0000644 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000645}
646
647static void console_scroll(int ydelta)
648{
649 TextConsole *s;
650 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000651
bellarde7f0ad52004-07-14 17:28:59 +0000652 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000653 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000654 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
681static void console_put_lf(TextConsole *s)
682{
683 TextCell *c;
684 int x, y1;
685
bellarde7f0ad52004-07-14 17:28:59 +0000686 s->y++;
687 if (s->y >= s->height) {
688 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000689
bellarde7f0ad52004-07-14 17:28:59 +0000690 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 = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000702 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000703 c++;
704 }
705 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000706 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000707 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
ths5fafdf22007-09-16 21:08:06 +0000714 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
715 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000716 (s->height - 1) * FONT_HEIGHT);
717 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000718 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000719 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000720 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;
bellarde7f0ad52004-07-14 17:28:59 +0000724 }
725 }
726}
727
pbrook6d6f7c22006-03-11 15:35:30 +0000728/* 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 */
732static void console_handle_escape(TextConsole *s)
733{
734 int i;
735
pbrook6d6f7c22006-03-11 15:35:30 +0000736 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
thsadb47962007-01-16 23:02:36 +0000825static 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
bellarde7f0ad52004-07-14 17:28:59 +0000835static void console_putchar(TextConsole *s, int ch)
836{
837 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000838 int y1, i;
839 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000840
841 switch(s->state) {
842 case TTY_STATE_NORM:
843 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000844 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000845 s->x = 0;
846 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000847 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000848 console_put_lf(s);
849 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000850 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000851 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000852 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000853 break;
854 case '\t': /* tabspace */
855 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000856 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000857 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;
thsadb47962007-01-16 23:02:36 +0000865 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;
pbrook6d6f7c22006-03-11 15:35:30 +0000871 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000872 s->state = TTY_STATE_ESC;
873 break;
874 default:
thsed8276a2007-02-10 22:37:56 +0000875 if (s->x >= s->width) {
876 /* line wrap */
877 s->x = 0;
878 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000879 }
bellarde7f0ad52004-07-14 17:28:59 +0000880 y1 = (s->y_base + s->y) % s->total_height;
881 c = &s->cells[y1 * s->width + s->x];
882 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000883 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000884 update_xy(s, s->x, s->y);
885 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000886 break;
887 }
888 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000889 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000890 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;
pbrook6d6f7c22006-03-11 15:35:30 +0000899 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000900 if (ch >= '0' && ch <= '9') {
901 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000902 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000903 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
904 }
905 } else {
906 s->nb_esc_params++;
907 if (ch == ';')
908 break;
thsadb47962007-01-16 23:02:36 +0000909#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
bellarde7f0ad52004-07-14 17:28:59 +0000913 s->state = TTY_STATE_NORM;
914 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000915 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;
bellarde7f0ad52004-07-14 17:28:59 +0000923 }
924 break;
thsadb47962007-01-16 23:02:36 +0000925 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 }
bellarde7f0ad52004-07-14 17:28:59 +00001026 break;
1027 }
thsadb47962007-01-16 23:02:36 +00001028 break;
1029 case 'm':
pbrook6d6f7c22006-03-11 15:35:30 +00001030 console_handle_escape(s);
bellarde7f0ad52004-07-14 17:28:59 +00001031 break;
thsadb47962007-01-16 23:02:36 +00001032 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;
bellarde7f0ad52004-07-14 17:28:59 +00001053 }
1054 }
1055}
1056
1057void console_select(unsigned int index)
1058{
1059 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001060
bellarde7f0ad52004-07-14 17:28:59 +00001061 if (index >= MAX_CONSOLES)
1062 return;
aliguori7d957bd2009-01-15 22:14:11 +00001063 active_console->g_width = ds_get_width(active_console->ds);
1064 active_console->g_height = ds_get_height(active_console->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001065 s = consoles[index];
1066 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001067 DisplayState *ds = s->ds;
bellarde7f0ad52004-07-14 17:28:59 +00001068 active_console = s;
aliguori68f00992009-01-21 18:59:12 +00001069 if (ds_get_bits_per_pixel(s->ds)) {
aliguori7b5d76d2009-03-13 15:02:13 +00001070 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
aliguori68f00992009-01-21 18:59:12 +00001071 } else {
1072 s->ds->surface->width = s->width;
1073 s->ds->surface->height = s->height;
1074 }
aliguori7d957bd2009-01-15 22:14:11 +00001075 dpy_resize(s->ds);
balrog4d3b6f62008-02-10 16:33:14 +00001076 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001077 }
1078}
1079
1080static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1081{
1082 TextConsole *s = chr->opaque;
1083 int i;
1084
pbrook14778c22009-01-21 03:02:52 +00001085 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;
bellarde7f0ad52004-07-14 17:28:59 +00001089 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);
pbrook14778c22009-01-21 03:02:52 +00001094 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 }
bellarde7f0ad52004-07-14 17:28:59 +00001099 return len;
1100}
1101
bellard6fcfafb2004-08-01 21:48:30 +00001102static 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
bellarde15d7372006-06-25 16:26:29 +00001117static void kbd_send_chars(void *opaque)
1118{
1119 TextConsole *s = opaque;
1120 int len;
1121 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001122
pbrooke5b0bc42007-01-27 23:46:43 +00001123 len = qemu_chr_can_read(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001124 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);
pbrooke5b0bc42007-01-27 23:46:43 +00001130 qemu_chr_read(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001131 }
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
bellarde7f0ad52004-07-14 17:28:59 +00001139/* called when an ascii key is pressed */
1140void kbd_put_keysym(int keysym)
1141{
1142 TextConsole *s;
1143 uint8_t buf[16], *q;
1144 int c;
1145
1146 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001147 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001148 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:
bellarde15d7372006-06-25 16:26:29 +00001164 /* 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 {
bellarde7f0ad52004-07-14 17:28:59 +00001179 *q++ = keysym;
bellarde15d7372006-06-25 16:26:29 +00001180 }
pbrooke5b0bc42007-01-27 23:46:43 +00001181 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001182 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1183 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001184 }
1185 break;
1186 }
1187}
1188
balrog4d3b6f62008-02-10 16:33:14 +00001189static void text_console_invalidate(void *opaque)
1190{
1191 TextConsole *s = (TextConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001192 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 }
balrog4d3b6f62008-02-10 16:33:14 +00001197 console_refresh(s);
1198}
1199
Anthony Liguoric227f092009-10-01 16:12:16 -05001200static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001201{
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
aliguori42aa98e2009-01-16 21:01:48 +00001227static TextConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001228{
aliguori3023f3322009-01-16 19:04:14 +00001229 int i;
1230 TextConsole *s;
1231 for (i = 0; i < nb_consoles; i++) {
1232 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001233 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f3322009-01-16 19:04:14 +00001234 return s;
1235 }
1236 return NULL;
1237}
1238
Anthony Liguoric227f092009-10-01 16:12:16 -05001239static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001240{
1241 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001242 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001243
1244 if (nb_consoles >= MAX_CONSOLES)
1245 return NULL;
1246 s = qemu_mallocz(sizeof(TextConsole));
thsaf3a9032007-07-11 23:14:59 +00001247 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1248 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001249 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001250 }
bellarde7f0ad52004-07-14 17:28:59 +00001251 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001252 s->console_type = console_type;
1253 if (console_type != GRAPHIC_CONSOLE) {
pbrook95219892006-04-09 01:06:34 +00001254 consoles[nb_consoles++] = s;
1255 } else {
1256 /* HACK: Put graphical consoles before text consoles. */
1257 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001258 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001259 break;
1260 consoles[i] = consoles[i - 1];
1261 }
1262 consoles[i] = s;
aliguori3023f3322009-01-16 19:04:14 +00001263 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001264 }
bellarde7f0ad52004-07-14 17:28:59 +00001265 return s;
1266}
1267
aliguori3023f3322009-01-16 19:04:14 +00001268DisplayState *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)
bellarde7f0ad52004-07-14 17:28:59 +00001273{
pbrook95219892006-04-09 01:06:34 +00001274 TextConsole *s;
aliguori3023f3322009-01-16 19:04:14 +00001275 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001276
aliguori3023f3322009-01-16 19:04:14 +00001277 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001278 ds->allocator = &default_allocator;
1279 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001280
thsaf3a9032007-07-11 23:14:59 +00001281 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f3322009-01-16 19:04:14 +00001282 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001283 qemu_free_displaysurface(ds);
aliguori3023f3322009-01-16 19:04:14 +00001284 qemu_free(ds);
1285 return NULL;
1286 }
pbrook95219892006-04-09 01:06:34 +00001287 s->hw_update = update;
1288 s->hw_invalidate = invalidate;
1289 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001290 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001291 s->hw = opaque;
aliguori3023f3322009-01-16 19:04:14 +00001292
aurel32f0f2f972009-01-16 21:13:49 +00001293 register_displaystate(ds);
aliguori3023f3322009-01-16 19:04:14 +00001294 return ds;
pbrook95219892006-04-09 01:06:34 +00001295}
1296
1297int is_graphic_console(void)
1298{
balrog4d3b6f62008-02-10 16:33:14 +00001299 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001300}
1301
balrogc21bbcf2008-09-24 03:32:33 +00001302int is_fixedsize_console(void)
1303{
1304 return active_console && active_console->console_type != TEXT_CONSOLE;
1305}
1306
balroga528b802007-10-30 22:38:53 +00001307void console_color_init(DisplayState *ds)
1308{
1309 int i, j;
1310 for (j = 0; j < 2; j++) {
1311 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001312 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001313 vga_get_color(ds, color_table_rgb[j][i]));
1314 }
1315 }
1316}
1317
aliguori2796dae2009-01-16 20:23:27 +00001318static int n_text_consoles;
1319static CharDriverState *text_consoles[128];
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001320static QemuOpts *text_console_opts[128];
aliguori2796dae2009-01-16 20:23:27 +00001321
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001322static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
bellarde7f0ad52004-07-14 17:28:59 +00001323{
bellarde7f0ad52004-07-14 17:28:59 +00001324 TextConsole *s;
thsaf3a9032007-07-11 23:14:59 +00001325 unsigned width;
1326 unsigned height;
bellarde7f0ad52004-07-14 17:28:59 +00001327 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001328
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001329 width = qemu_opt_get_number(opts, "width", 0);
1330 if (width == 0)
1331 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1332
1333 height = qemu_opt_get_number(opts, "height", 0);
1334 if (height == 0)
1335 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1336
1337 if (width == 0 || height == 0) {
1338 s = new_console(ds, TEXT_CONSOLE);
1339 width = ds_get_width(s->ds);
1340 height = ds_get_height(s->ds);
1341 } else {
1342 s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
1343 }
1344
bellarde7f0ad52004-07-14 17:28:59 +00001345 if (!s) {
1346 free(chr);
aliguorifdb868e2009-01-16 21:06:20 +00001347 return;
bellarde7f0ad52004-07-14 17:28:59 +00001348 }
bellarde7f0ad52004-07-14 17:28:59 +00001349 chr->opaque = s;
1350 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001351 chr->chr_send_event = console_send_event;
1352
pbrooke5b0bc42007-01-27 23:46:43 +00001353 s->chr = chr;
bellarde15d7372006-06-25 16:26:29 +00001354 s->out_fifo.buf = s->out_fifo_buf;
1355 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1356 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
aliguori3023f3322009-01-16 19:04:14 +00001357 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001358
bellarde7f0ad52004-07-14 17:28:59 +00001359 if (!color_inited) {
1360 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001361 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001362 }
1363 s->y_displayed = 0;
1364 s->y_base = 0;
1365 s->total_height = DEFAULT_BACKSCROLL;
1366 s->x = 0;
1367 s->y = 0;
thsaf3a9032007-07-11 23:14:59 +00001368 s->g_width = width;
1369 s->g_height = height;
pbrook6d6f7c22006-03-11 15:35:30 +00001370
balrog4d3b6f62008-02-10 16:33:14 +00001371 s->hw_invalidate = text_console_invalidate;
1372 s->hw_text_update = text_console_update;
1373 s->hw = s;
1374
pbrook6d6f7c22006-03-11 15:35:30 +00001375 /* Set text attribute defaults */
1376 s->t_attrib_default.bold = 0;
1377 s->t_attrib_default.uline = 0;
1378 s->t_attrib_default.blink = 0;
1379 s->t_attrib_default.invers = 0;
1380 s->t_attrib_default.unvisible = 0;
1381 s->t_attrib_default.fgcol = COLOR_WHITE;
1382 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001383 /* set current text attributes to default */
1384 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001385 text_console_resize(s);
1386
ths86e94de2007-01-05 22:01:59 +00001387 qemu_chr_reset(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001388 if (chr->init)
1389 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001390}
pbrookc60e08d2008-07-01 16:24:38 +00001391
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001392CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001393{
1394 CharDriverState *chr;
1395
1396 chr = qemu_mallocz(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001397
1398 if (n_text_consoles == 128) {
1399 fprintf(stderr, "Too many text consoles\n");
1400 exit(1);
1401 }
1402 text_consoles[n_text_consoles] = chr;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001403 text_console_opts[n_text_consoles] = opts;
aliguori2796dae2009-01-16 20:23:27 +00001404 n_text_consoles++;
1405
1406 return chr;
1407}
1408
1409void text_consoles_set_display(DisplayState *ds)
1410{
1411 int i;
1412
1413 for (i = 0; i < n_text_consoles; i++) {
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001414 text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
1415 qemu_opts_del(text_console_opts[i]);
1416 text_console_opts[i] = NULL;
aliguori2796dae2009-01-16 20:23:27 +00001417 }
1418
1419 n_text_consoles = 0;
1420}
1421
aliguori3023f3322009-01-16 19:04:14 +00001422void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001423{
aliguori42aa98e2009-01-16 21:01:48 +00001424 TextConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001425 if (!s) return;
1426
aliguori3023f3322009-01-16 19:04:14 +00001427 s->g_width = width;
1428 s->g_height = height;
1429 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001430 ds->surface = qemu_resize_displaysurface(ds, width, height);
aliguori3023f3322009-01-16 19:04:14 +00001431 dpy_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001432 }
1433}
balrog38334f72008-09-24 02:21:24 +00001434
aliguori3023f3322009-01-16 19:04:14 +00001435void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1436 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001437{
aliguori3023f3322009-01-16 19:04:14 +00001438 if (is_graphic_console()) {
1439 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001440 }
1441}
aliguori7d957bd2009-01-15 22:14:11 +00001442
malc0da2ea12009-01-23 19:56:19 +00001443PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001444{
1445 PixelFormat pf;
1446
1447 memset(&pf, 0x00, sizeof(PixelFormat));
1448
1449 pf.bits_per_pixel = bpp;
1450 pf.bytes_per_pixel = bpp / 8;
1451 pf.depth = bpp == 32 ? 24 : bpp;
1452
1453 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001454 case 24:
1455 pf.rmask = 0x000000FF;
1456 pf.gmask = 0x0000FF00;
1457 pf.bmask = 0x00FF0000;
1458 pf.rmax = 255;
1459 pf.gmax = 255;
1460 pf.bmax = 255;
1461 pf.rshift = 0;
1462 pf.gshift = 8;
1463 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001464 pf.rbits = 8;
1465 pf.gbits = 8;
1466 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001467 break;
malc0da2ea12009-01-23 19:56:19 +00001468 case 32:
1469 pf.rmask = 0x0000FF00;
1470 pf.gmask = 0x00FF0000;
1471 pf.bmask = 0xFF000000;
1472 pf.amask = 0x00000000;
1473 pf.amax = 255;
1474 pf.rmax = 255;
1475 pf.gmax = 255;
1476 pf.bmax = 255;
1477 pf.ashift = 0;
1478 pf.rshift = 8;
1479 pf.gshift = 16;
1480 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001481 pf.rbits = 8;
1482 pf.gbits = 8;
1483 pf.bbits = 8;
1484 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001485 break;
1486 default:
1487 break;
1488 }
1489 return pf;
1490}
1491
1492PixelFormat qemu_default_pixelformat(int bpp)
1493{
1494 PixelFormat pf;
1495
1496 memset(&pf, 0x00, sizeof(PixelFormat));
1497
1498 pf.bits_per_pixel = bpp;
1499 pf.bytes_per_pixel = bpp / 8;
1500 pf.depth = bpp == 32 ? 24 : bpp;
1501
1502 switch (bpp) {
aliguori7d957bd2009-01-15 22:14:11 +00001503 case 16:
1504 pf.rmask = 0x0000F800;
1505 pf.gmask = 0x000007E0;
1506 pf.bmask = 0x0000001F;
1507 pf.rmax = 31;
1508 pf.gmax = 63;
1509 pf.bmax = 31;
1510 pf.rshift = 11;
1511 pf.gshift = 5;
1512 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001513 pf.rbits = 5;
1514 pf.gbits = 6;
1515 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001516 break;
1517 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001518 pf.rmask = 0x00FF0000;
1519 pf.gmask = 0x0000FF00;
1520 pf.bmask = 0x000000FF;
1521 pf.rmax = 255;
1522 pf.gmax = 255;
1523 pf.bmax = 255;
1524 pf.rshift = 16;
1525 pf.gshift = 8;
1526 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001527 pf.rbits = 8;
1528 pf.gbits = 8;
1529 pf.bbits = 8;
malc0da2ea12009-01-23 19:56:19 +00001530 case 32:
1531 pf.rmask = 0x00FF0000;
1532 pf.gmask = 0x0000FF00;
1533 pf.bmask = 0x000000FF;
1534 pf.amax = 255;
1535 pf.rmax = 255;
1536 pf.gmax = 255;
1537 pf.bmax = 255;
1538 pf.ashift = 24;
1539 pf.rshift = 16;
1540 pf.gshift = 8;
1541 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001542 pf.rbits = 8;
1543 pf.gbits = 8;
1544 pf.bbits = 8;
1545 pf.abits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001546 break;
1547 default:
1548 break;
1549 }
1550 return pf;
1551}
1552
aliguori7b5d76d2009-03-13 15:02:13 +00001553DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
aliguori7d957bd2009-01-15 22:14:11 +00001554{
1555 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
aliguori7d957bd2009-01-15 22:14:11 +00001556
1557 surface->width = width;
1558 surface->height = height;
aliguori7b5d76d2009-03-13 15:02:13 +00001559 surface->linesize = width * 4;
1560 surface->pf = qemu_default_pixelformat(32);
Juan Quintelae2542fe2009-07-27 16:13:06 +02001561#ifdef HOST_WORDS_BIGENDIAN
aliguori7d957bd2009-01-15 22:14:11 +00001562 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1563#else
1564 surface->flags = QEMU_ALLOCATED_FLAG;
1565#endif
1566 surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
aliguori7d957bd2009-01-15 22:14:11 +00001567
1568 return surface;
1569}
1570
aliguori7b5d76d2009-03-13 15:02:13 +00001571DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1572 int width, int height)
aliguori7d957bd2009-01-15 22:14:11 +00001573{
1574 surface->width = width;
1575 surface->height = height;
aliguori7b5d76d2009-03-13 15:02:13 +00001576 surface->linesize = width * 4;
1577 surface->pf = qemu_default_pixelformat(32);
aliguori7d957bd2009-01-15 22:14:11 +00001578 if (surface->flags & QEMU_ALLOCATED_FLAG)
1579 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1580 else
1581 surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
Juan Quintelae2542fe2009-07-27 16:13:06 +02001582#ifdef HOST_WORDS_BIGENDIAN
aliguori7d957bd2009-01-15 22:14:11 +00001583 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1584#else
1585 surface->flags = QEMU_ALLOCATED_FLAG;
1586#endif
1587
1588 return surface;
1589}
1590
1591DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1592 int linesize, uint8_t *data)
1593{
1594 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
aliguori7d957bd2009-01-15 22:14:11 +00001595
1596 surface->width = width;
1597 surface->height = height;
1598 surface->linesize = linesize;
1599 surface->pf = qemu_default_pixelformat(bpp);
Juan Quintelae2542fe2009-07-27 16:13:06 +02001600#ifdef HOST_WORDS_BIGENDIAN
aliguori7d957bd2009-01-15 22:14:11 +00001601 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1602#endif
1603 surface->data = data;
1604
1605 return surface;
1606}
1607
aliguori7b5d76d2009-03-13 15:02:13 +00001608void defaultallocator_free_displaysurface(DisplaySurface *surface)
aliguori7d957bd2009-01-15 22:14:11 +00001609{
1610 if (surface == NULL)
1611 return;
1612 if (surface->flags & QEMU_ALLOCATED_FLAG)
1613 qemu_free(surface->data);
1614 qemu_free(surface);
1615}