]> git.proxmox.com Git - qemu.git/blame - console.c
qemu-nbd: print error messages from the daemon through a pipe
[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 }
1012 break;
1013 }
e7f0ad58 1014 case 'K':
adb47967
TS
1015 switch (s->esc_params[0]) {
1016 case 0:
e7f0ad58 1017 /* clear to eol */
e7f0ad58 1018 for(x = s->x; x < s->width; x++) {
adb47967 1019 console_clear_xy(s, x, s->y);
e7f0ad58
FB
1020 }
1021 break;
adb47967
TS
1022 case 1:
1023 /* clear from beginning of line */
1024 for (x = 0; x <= s->x; x++) {
1025 console_clear_xy(s, x, s->y);
1026 }
1027 break;
1028 case 2:
1029 /* clear entire line */
1030 for(x = 0; x < s->width; x++) {
1031 console_clear_xy(s, x, s->y);
1032 }
e7f0ad58
FB
1033 break;
1034 }
adb47967
TS
1035 break;
1036 case 'm':
6d6f7c28 1037 console_handle_escape(s);
e7f0ad58 1038 break;
adb47967
TS
1039 case 'n':
1040 /* report cursor position */
1041 /* TODO: send ESC[row;colR */
1042 break;
1043 case 's':
1044 /* save cursor position */
1045 s->x_saved = s->x;
1046 s->y_saved = s->y;
1047 break;
1048 case 'u':
1049 /* restore cursor position */
1050 s->x = s->x_saved;
1051 s->y = s->y_saved;
1052 break;
1053 default:
1054#ifdef DEBUG_CONSOLE
1055 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1056#endif
1057 break;
1058 }
1059 break;
e7f0ad58
FB
1060 }
1061 }
1062}
1063
1064void console_select(unsigned int index)
1065{
1066 TextConsole *s;
6d6f7c28 1067
e7f0ad58
FB
1068 if (index >= MAX_CONSOLES)
1069 return;
358664cc
SH
1070 if (active_console) {
1071 active_console->g_width = ds_get_width(active_console->ds);
1072 active_console->g_height = ds_get_height(active_console->ds);
1073 }
e7f0ad58
FB
1074 s = consoles[index];
1075 if (s) {
7d957bd8 1076 DisplayState *ds = s->ds;
e7f0ad58 1077 active_console = s;
68f00996 1078 if (ds_get_bits_per_pixel(s->ds)) {
7b5d76da 1079 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
68f00996
AL
1080 } else {
1081 s->ds->surface->width = s->width;
1082 s->ds->surface->height = s->height;
1083 }
7d957bd8 1084 dpy_resize(s->ds);
4d3b6f6e 1085 vga_hw_invalidate();
e7f0ad58
FB
1086 }
1087}
1088
1089static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1090{
1091 TextConsole *s = chr->opaque;
1092 int i;
1093
14778c20
PB
1094 s->update_x0 = s->width * FONT_WIDTH;
1095 s->update_y0 = s->height * FONT_HEIGHT;
1096 s->update_x1 = 0;
1097 s->update_y1 = 0;
e7f0ad58
FB
1098 console_show_cursor(s, 0);
1099 for(i = 0; i < len; i++) {
1100 console_putchar(s, buf[i]);
1101 }
1102 console_show_cursor(s, 1);
14778c20
PB
1103 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1104 dpy_update(s->ds, s->update_x0, s->update_y0,
1105 s->update_x1 - s->update_x0,
1106 s->update_y1 - s->update_y0);
1107 }
e7f0ad58
FB
1108 return len;
1109}
1110
e15d7371
FB
1111static void kbd_send_chars(void *opaque)
1112{
1113 TextConsole *s = opaque;
1114 int len;
1115 uint8_t buf[16];
3b46e624 1116
909cda12 1117 len = qemu_chr_be_can_write(s->chr);
e15d7371
FB
1118 if (len > s->out_fifo.count)
1119 len = s->out_fifo.count;
1120 if (len > 0) {
1121 if (len > sizeof(buf))
1122 len = sizeof(buf);
1123 qemu_fifo_read(&s->out_fifo, buf, len);
fa5efccb 1124 qemu_chr_be_write(s->chr, buf, len);
e15d7371
FB
1125 }
1126 /* characters are pending: we send them a bit later (XXX:
1127 horrible, should change char device API) */
1128 if (s->out_fifo.count > 0) {
7bd427d8 1129 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
e15d7371
FB
1130 }
1131}
1132
e7f0ad58
FB
1133/* called when an ascii key is pressed */
1134void kbd_put_keysym(int keysym)
1135{
1136 TextConsole *s;
1137 uint8_t buf[16], *q;
1138 int c;
1139
1140 s = active_console;
af3a9031 1141 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
1142 return;
1143
1144 switch(keysym) {
1145 case QEMU_KEY_CTRL_UP:
1146 console_scroll(-1);
1147 break;
1148 case QEMU_KEY_CTRL_DOWN:
1149 console_scroll(1);
1150 break;
1151 case QEMU_KEY_CTRL_PAGEUP:
1152 console_scroll(-10);
1153 break;
1154 case QEMU_KEY_CTRL_PAGEDOWN:
1155 console_scroll(10);
1156 break;
1157 default:
e15d7371
FB
1158 /* convert the QEMU keysym to VT100 key string */
1159 q = buf;
1160 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1161 *q++ = '\033';
1162 *q++ = '[';
1163 c = keysym - 0xe100;
1164 if (c >= 10)
1165 *q++ = '0' + (c / 10);
1166 *q++ = '0' + (c % 10);
1167 *q++ = '~';
1168 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1169 *q++ = '\033';
1170 *q++ = '[';
1171 *q++ = keysym & 0xff;
4104833f
PB
1172 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1173 console_puts(s->chr, (const uint8_t *) "\r", 1);
1174 *q++ = '\n';
e15d7371 1175 } else {
4104833f
PB
1176 *q++ = keysym;
1177 }
1178 if (s->echo) {
1179 console_puts(s->chr, buf, q - buf);
e15d7371 1180 }
e5b0bc44 1181 if (s->chr->chr_read) {
e15d7371
FB
1182 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1183 kbd_send_chars(s);
e7f0ad58
FB
1184 }
1185 break;
1186 }
1187}
1188
4d3b6f6e
AZ
1189static void text_console_invalidate(void *opaque)
1190{
1191 TextConsole *s = (TextConsole *) opaque;
68f00996
AL
1192 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1193 s->g_width = ds_get_width(s->ds);
1194 s->g_height = ds_get_height(s->ds);
1195 text_console_resize(s);
1196 }
4d3b6f6e
AZ
1197 console_refresh(s);
1198}
1199
c227f099 1200static void text_console_update(void *opaque, console_ch_t *chardata)
4d3b6f6e
AZ
1201{
1202 TextConsole *s = (TextConsole *) opaque;
1203 int i, j, src;
1204
1205 if (s->text_x[0] <= s->text_x[1]) {
1206 src = (s->y_base + s->text_y[0]) * s->width;
1207 chardata += s->text_y[0] * s->width;
1208 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1209 for (j = 0; j < s->width; j ++, src ++)
1210 console_write_ch(chardata ++, s->cells[src].ch |
1211 (s->cells[src].t_attrib.fgcol << 12) |
1212 (s->cells[src].t_attrib.bgcol << 8) |
1213 (s->cells[src].t_attrib.bold << 21));
1214 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1215 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1216 s->text_x[0] = s->width;
1217 s->text_y[0] = s->height;
1218 s->text_x[1] = 0;
1219 s->text_y[1] = 0;
1220 }
1221 if (s->cursor_invalidate) {
1222 dpy_cursor(s->ds, s->x, s->y);
1223 s->cursor_invalidate = 0;
1224 }
1225}
1226
42aa98e8 1227static TextConsole *get_graphic_console(DisplayState *ds)
a147d62b 1228{
3023f332
AL
1229 int i;
1230 TextConsole *s;
1231 for (i = 0; i < nb_consoles; i++) {
1232 s = consoles[i];
42aa98e8 1233 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
3023f332
AL
1234 return s;
1235 }
1236 return NULL;
1237}
1238
c227f099 1239static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
e7f0ad58
FB
1240{
1241 TextConsole *s;
95219897 1242 int i;
e7f0ad58
FB
1243
1244 if (nb_consoles >= MAX_CONSOLES)
1245 return NULL;
7267c094 1246 s = g_malloc0(sizeof(TextConsole));
af3a9031
TS
1247 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1248 (console_type == GRAPHIC_CONSOLE))) {
e7f0ad58 1249 active_console = s;
af3a9031 1250 }
e7f0ad58 1251 s->ds = ds;
af3a9031
TS
1252 s->console_type = console_type;
1253 if (console_type != GRAPHIC_CONSOLE) {
f81bdefb 1254 s->index = nb_consoles;
95219897
PB
1255 consoles[nb_consoles++] = s;
1256 } else {
1257 /* HACK: Put graphical consoles before text consoles. */
1258 for (i = nb_consoles; i > 0; i--) {
af3a9031 1259 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
95219897
PB
1260 break;
1261 consoles[i] = consoles[i - 1];
f81bdefb 1262 consoles[i]->index = i;
95219897 1263 }
f81bdefb 1264 s->index = i;
95219897 1265 consoles[i] = s;
3023f332 1266 nb_consoles++;
95219897
PB
1267 }
1268 return s;
1269}
1270
98b50080
PB
1271static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1272{
7267c094 1273 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
98b50080 1274
ffe8b821
JS
1275 int linesize = width * 4;
1276 qemu_alloc_display(surface, width, height, linesize,
1277 qemu_default_pixelformat(32), 0);
98b50080
PB
1278 return surface;
1279}
1280
1281static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1282 int width, int height)
1283{
ffe8b821
JS
1284 int linesize = width * 4;
1285 qemu_alloc_display(surface, width, height, linesize,
1286 qemu_default_pixelformat(32), 0);
1287 return surface;
1288}
1289
1290void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1291 int linesize, PixelFormat pf, int newflags)
1292{
1293 void *data;
98b50080
PB
1294 surface->width = width;
1295 surface->height = height;
ffe8b821
JS
1296 surface->linesize = linesize;
1297 surface->pf = pf;
1298 if (surface->flags & QEMU_ALLOCATED_FLAG) {
7267c094 1299 data = g_realloc(surface->data,
ffe8b821
JS
1300 surface->linesize * surface->height);
1301 } else {
7267c094 1302 data = g_malloc(surface->linesize * surface->height);
ffe8b821
JS
1303 }
1304 surface->data = (uint8_t *)data;
1305 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
98b50080 1306#ifdef HOST_WORDS_BIGENDIAN
ffe8b821 1307 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
98b50080 1308#endif
98b50080
PB
1309}
1310
1311DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1312 int linesize, uint8_t *data)
1313{
7267c094 1314 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
98b50080
PB
1315
1316 surface->width = width;
1317 surface->height = height;
1318 surface->linesize = linesize;
1319 surface->pf = qemu_default_pixelformat(bpp);
1320#ifdef HOST_WORDS_BIGENDIAN
1321 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1322#endif
1323 surface->data = data;
1324
1325 return surface;
1326}
1327
1328static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1329{
1330 if (surface == NULL)
1331 return;
1332 if (surface->flags & QEMU_ALLOCATED_FLAG)
7267c094
AL
1333 g_free(surface->data);
1334 g_free(surface);
98b50080
PB
1335}
1336
1337static struct DisplayAllocator default_allocator = {
1338 defaultallocator_create_displaysurface,
1339 defaultallocator_resize_displaysurface,
1340 defaultallocator_free_displaysurface
1341};
1342
1343static void dumb_display_init(void)
1344{
7267c094 1345 DisplayState *ds = g_malloc0(sizeof(DisplayState));
1802651c
JK
1346 int width = 640;
1347 int height = 480;
1348
98b50080 1349 ds->allocator = &default_allocator;
1802651c
JK
1350 if (is_fixedsize_console()) {
1351 width = active_console->g_width;
1352 height = active_console->g_height;
1353 }
1354 ds->surface = qemu_create_displaysurface(ds, width, height);
98b50080
PB
1355 register_displaystate(ds);
1356}
1357
1358/***********************************************************/
1359/* register display */
1360
1361void register_displaystate(DisplayState *ds)
1362{
1363 DisplayState **s;
1364 s = &display_state;
1365 while (*s != NULL)
1366 s = &(*s)->next;
1367 ds->next = NULL;
1368 *s = ds;
1369}
1370
1371DisplayState *get_displaystate(void)
1372{
1373 if (!display_state) {
1374 dumb_display_init ();
1375 }
1376 return display_state;
1377}
1378
1379DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1380{
1381 if(ds->allocator == &default_allocator) {
1382 DisplaySurface *surf;
1383 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1384 defaultallocator_free_displaysurface(ds->surface);
1385 ds->surface = surf;
1386 ds->allocator = da;
1387 }
1388 return ds->allocator;
1389}
1390
3023f332
AL
1391DisplayState *graphic_console_init(vga_hw_update_ptr update,
1392 vga_hw_invalidate_ptr invalidate,
1393 vga_hw_screen_dump_ptr screen_dump,
1394 vga_hw_text_update_ptr text_update,
1395 void *opaque)
95219897
PB
1396{
1397 TextConsole *s;
3023f332 1398 DisplayState *ds;
f0f2f976 1399
7267c094 1400 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
7b5d76da
AL
1401 ds->allocator = &default_allocator;
1402 ds->surface = qemu_create_displaysurface(ds, 640, 480);
95219897 1403
af3a9031 1404 s = new_console(ds, GRAPHIC_CONSOLE);
3023f332 1405 if (s == NULL) {
7b5d76da 1406 qemu_free_displaysurface(ds);
7267c094 1407 g_free(ds);
3023f332
AL
1408 return NULL;
1409 }
95219897
PB
1410 s->hw_update = update;
1411 s->hw_invalidate = invalidate;
1412 s->hw_screen_dump = screen_dump;
4d3b6f6e 1413 s->hw_text_update = text_update;
95219897 1414 s->hw = opaque;
3023f332 1415
f0f2f976 1416 register_displaystate(ds);
3023f332 1417 return ds;
e7f0ad58
FB
1418}
1419
95219897 1420int is_graphic_console(void)
e7f0ad58 1421{
4d3b6f6e 1422 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
e7f0ad58
FB
1423}
1424
c21bbcfa
AZ
1425int is_fixedsize_console(void)
1426{
1427 return active_console && active_console->console_type != TEXT_CONSOLE;
1428}
1429
a528b80c
AZ
1430void console_color_init(DisplayState *ds)
1431{
1432 int i, j;
1433 for (j = 0; j < 2; j++) {
1434 for (i = 0; i < 8; i++) {
f0f2f976 1435 color_table[j][i] = col_expand(ds,
a528b80c
AZ
1436 vga_get_color(ds, color_table_rgb[j][i]));
1437 }
1438 }
1439}
1440
2796dae0
AL
1441static int n_text_consoles;
1442static CharDriverState *text_consoles[128];
2796dae0 1443
4104833f
PB
1444static void text_console_set_echo(CharDriverState *chr, bool echo)
1445{
1446 TextConsole *s = chr->opaque;
1447
1448 s->echo = echo;
1449}
1450
44b37b93 1451static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
e7f0ad58 1452{
e7f0ad58 1453 TextConsole *s;
e7f0ad58 1454 static int color_inited;
6d6f7c28 1455
491e114a 1456 s = chr->opaque;
6ea314d9 1457
e7f0ad58 1458 chr->chr_write = console_puts;
6fcfafb7 1459
e15d7371
FB
1460 s->out_fifo.buf = s->out_fifo_buf;
1461 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
7bd427d8 1462 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
3023f332 1463 s->ds = ds;
3b46e624 1464
e7f0ad58
FB
1465 if (!color_inited) {
1466 color_inited = 1;
a528b80c 1467 console_color_init(s->ds);
e7f0ad58
FB
1468 }
1469 s->y_displayed = 0;
1470 s->y_base = 0;
1471 s->total_height = DEFAULT_BACKSCROLL;
1472 s->x = 0;
1473 s->y = 0;
491e114a
PB
1474 if (s->console_type == TEXT_CONSOLE) {
1475 s->g_width = ds_get_width(s->ds);
1476 s->g_height = ds_get_height(s->ds);
1477 }
6d6f7c28 1478
4d3b6f6e
AZ
1479 s->hw_invalidate = text_console_invalidate;
1480 s->hw_text_update = text_console_update;
1481 s->hw = s;
1482
6d6f7c28
PB
1483 /* Set text attribute defaults */
1484 s->t_attrib_default.bold = 0;
1485 s->t_attrib_default.uline = 0;
1486 s->t_attrib_default.blink = 0;
1487 s->t_attrib_default.invers = 0;
1488 s->t_attrib_default.unvisible = 0;
1489 s->t_attrib_default.fgcol = COLOR_WHITE;
1490 s->t_attrib_default.bgcol = COLOR_BLACK;
6d6f7c28
PB
1491 /* set current text attributes to default */
1492 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1493 text_console_resize(s);
1494
51bfa4d3
GH
1495 if (chr->label) {
1496 char msg[128];
1497 int len;
1498
735ba588 1499 s->t_attrib.bgcol = COLOR_BLUE;
51bfa4d3
GH
1500 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1501 console_puts(chr, (uint8_t*)msg, len);
735ba588 1502 s->t_attrib = s->t_attrib_default;
51bfa4d3
GH
1503 }
1504
127338e6 1505 qemu_chr_generic_open(chr);
ceecf1d1
AJ
1506 if (chr->init)
1507 chr->init(chr);
e7f0ad58 1508}
c60e08d9 1509
6e1db57b 1510int text_console_init(QemuOpts *opts, CharDriverState **_chr)
2796dae0
AL
1511{
1512 CharDriverState *chr;
491e114a
PB
1513 TextConsole *s;
1514 unsigned width;
1515 unsigned height;
2796dae0 1516
7267c094 1517 chr = g_malloc0(sizeof(CharDriverState));
2796dae0
AL
1518
1519 if (n_text_consoles == 128) {
1520 fprintf(stderr, "Too many text consoles\n");
1521 exit(1);
1522 }
1523 text_consoles[n_text_consoles] = chr;
2796dae0
AL
1524 n_text_consoles++;
1525
491e114a
PB
1526 width = qemu_opt_get_number(opts, "width", 0);
1527 if (width == 0)
1528 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1529
1530 height = qemu_opt_get_number(opts, "height", 0);
1531 if (height == 0)
1532 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1533
1534 if (width == 0 || height == 0) {
1535 s = new_console(NULL, TEXT_CONSOLE);
1536 } else {
1537 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1538 }
1539
1540 if (!s) {
5354d083 1541 g_free(chr);
6e1db57b 1542 return -EBUSY;
491e114a
PB
1543 }
1544
1545 s->chr = chr;
1546 s->g_width = width;
1547 s->g_height = height;
1548 chr->opaque = s;
4104833f 1549 chr->chr_set_echo = text_console_set_echo;
6e1db57b
KW
1550
1551 *_chr = chr;
1552 return 0;
2796dae0
AL
1553}
1554
1555void text_consoles_set_display(DisplayState *ds)
1556{
1557 int i;
1558
1559 for (i = 0; i < n_text_consoles; i++) {
44b37b93 1560 text_console_do_init(text_consoles[i], ds);
2796dae0
AL
1561 }
1562
1563 n_text_consoles = 0;
1564}
1565
3023f332 1566void qemu_console_resize(DisplayState *ds, int width, int height)
c60e08d9 1567{
42aa98e8 1568 TextConsole *s = get_graphic_console(ds);
f497f140
AL
1569 if (!s) return;
1570
3023f332
AL
1571 s->g_width = width;
1572 s->g_height = height;
1573 if (is_graphic_console()) {
7b5d76da 1574 ds->surface = qemu_resize_displaysurface(ds, width, height);
3023f332 1575 dpy_resize(ds);
c60e08d9
PB
1576 }
1577}
38334f76 1578
3023f332
AL
1579void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1580 int dst_x, int dst_y, int w, int h)
c21bbcfa 1581{
3023f332
AL
1582 if (is_graphic_console()) {
1583 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
38334f76
AZ
1584 }
1585}
7d957bd8 1586
0da2ea1b 1587PixelFormat qemu_different_endianness_pixelformat(int bpp)
7d957bd8
AL
1588{
1589 PixelFormat pf;
1590
1591 memset(&pf, 0x00, sizeof(PixelFormat));
1592
1593 pf.bits_per_pixel = bpp;
1594 pf.bytes_per_pixel = bpp / 8;
1595 pf.depth = bpp == 32 ? 24 : bpp;
1596
1597 switch (bpp) {
0da2ea1b 1598 case 24:
1599 pf.rmask = 0x000000FF;
1600 pf.gmask = 0x0000FF00;
1601 pf.bmask = 0x00FF0000;
1602 pf.rmax = 255;
1603 pf.gmax = 255;
1604 pf.bmax = 255;
1605 pf.rshift = 0;
1606 pf.gshift = 8;
1607 pf.bshift = 16;
90a1e3c0
AL
1608 pf.rbits = 8;
1609 pf.gbits = 8;
1610 pf.bbits = 8;
7d957bd8 1611 break;
0da2ea1b 1612 case 32:
1613 pf.rmask = 0x0000FF00;
1614 pf.gmask = 0x00FF0000;
1615 pf.bmask = 0xFF000000;
1616 pf.amask = 0x00000000;
1617 pf.amax = 255;
1618 pf.rmax = 255;
1619 pf.gmax = 255;
1620 pf.bmax = 255;
1621 pf.ashift = 0;
1622 pf.rshift = 8;
1623 pf.gshift = 16;
1624 pf.bshift = 24;
90a1e3c0
AL
1625 pf.rbits = 8;
1626 pf.gbits = 8;
1627 pf.bbits = 8;
1628 pf.abits = 8;
0da2ea1b 1629 break;
1630 default:
1631 break;
1632 }
1633 return pf;
1634}
1635
1636PixelFormat qemu_default_pixelformat(int bpp)
1637{
1638 PixelFormat pf;
1639
1640 memset(&pf, 0x00, sizeof(PixelFormat));
1641
1642 pf.bits_per_pixel = bpp;
1643 pf.bytes_per_pixel = bpp / 8;
1644 pf.depth = bpp == 32 ? 24 : bpp;
1645
1646 switch (bpp) {
b6278084
GH
1647 case 15:
1648 pf.bits_per_pixel = 16;
1649 pf.bytes_per_pixel = 2;
1650 pf.rmask = 0x00007c00;
1651 pf.gmask = 0x000003E0;
1652 pf.bmask = 0x0000001F;
1653 pf.rmax = 31;
1654 pf.gmax = 31;
1655 pf.bmax = 31;
1656 pf.rshift = 10;
1657 pf.gshift = 5;
1658 pf.bshift = 0;
1659 pf.rbits = 5;
1660 pf.gbits = 5;
1661 pf.bbits = 5;
1662 break;
7d957bd8
AL
1663 case 16:
1664 pf.rmask = 0x0000F800;
1665 pf.gmask = 0x000007E0;
1666 pf.bmask = 0x0000001F;
1667 pf.rmax = 31;
1668 pf.gmax = 63;
1669 pf.bmax = 31;
1670 pf.rshift = 11;
1671 pf.gshift = 5;
1672 pf.bshift = 0;
90a1e3c0
AL
1673 pf.rbits = 5;
1674 pf.gbits = 6;
1675 pf.bbits = 5;
7d957bd8
AL
1676 break;
1677 case 24:
0da2ea1b 1678 pf.rmask = 0x00FF0000;
1679 pf.gmask = 0x0000FF00;
1680 pf.bmask = 0x000000FF;
1681 pf.rmax = 255;
1682 pf.gmax = 255;
1683 pf.bmax = 255;
1684 pf.rshift = 16;
1685 pf.gshift = 8;
1686 pf.bshift = 0;
90a1e3c0
AL
1687 pf.rbits = 8;
1688 pf.gbits = 8;
1689 pf.bbits = 8;
7d957bd8
AL
1690 case 32:
1691 pf.rmask = 0x00FF0000;
1692 pf.gmask = 0x0000FF00;
1693 pf.bmask = 0x000000FF;
0da2ea1b 1694 pf.amax = 255;
7d957bd8
AL
1695 pf.rmax = 255;
1696 pf.gmax = 255;
1697 pf.bmax = 255;
0da2ea1b 1698 pf.ashift = 24;
7d957bd8
AL
1699 pf.rshift = 16;
1700 pf.gshift = 8;
1701 pf.bshift = 0;
90a1e3c0
AL
1702 pf.rbits = 8;
1703 pf.gbits = 8;
1704 pf.bbits = 8;
1705 pf.abits = 8;
7d957bd8
AL
1706 break;
1707 default:
1708 break;
1709 }
1710 return pf;
1711}