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