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