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