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