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