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