]> git.proxmox.com Git - qemu.git/blame - console.c
64bit->win32 cross build fix.
[qemu.git] / console.c
CommitLineData
e7f0ad58
FB
1/*
2 * QEMU graphical console
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
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 */
24#include "vl.h"
25
6d6f7c28 26//#define DEBUG_CONSOLE
e7f0ad58
FB
27#define DEFAULT_BACKSCROLL 512
28#define MAX_CONSOLES 12
29
26489844
FB
30#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
31#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
e7f0ad58 32
6d6f7c28
PB
33typedef struct TextAttributes {
34 uint8_t fgcol:4;
35 uint8_t bgcol:4;
36 uint8_t bold:1;
37 uint8_t uline:1;
38 uint8_t blink:1;
39 uint8_t invers:1;
40 uint8_t unvisible:1;
41} TextAttributes;
42
e7f0ad58
FB
43typedef struct TextCell {
44 uint8_t ch;
6d6f7c28 45 TextAttributes t_attrib;
e7f0ad58
FB
46} TextCell;
47
48#define MAX_ESC_PARAMS 3
49
50enum TTYState {
51 TTY_STATE_NORM,
52 TTY_STATE_ESC,
53 TTY_STATE_CSI,
54};
55
e15d7371
FB
56typedef struct QEMUFIFO {
57 uint8_t *buf;
58 int buf_size;
59 int count, wptr, rptr;
60} QEMUFIFO;
61
62int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
63{
64 int l, len;
65
66 l = f->buf_size - f->count;
67 if (len1 > l)
68 len1 = l;
69 len = len1;
70 while (len > 0) {
71 l = f->buf_size - f->wptr;
72 if (l > len)
73 l = len;
74 memcpy(f->buf + f->wptr, buf, l);
75 f->wptr += l;
76 if (f->wptr >= f->buf_size)
77 f->wptr = 0;
78 buf += l;
79 len -= l;
80 }
81 f->count += len1;
82 return len1;
83}
84
85int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
86{
87 int l, len;
88
89 if (len1 > f->count)
90 len1 = f->count;
91 len = len1;
92 while (len > 0) {
93 l = f->buf_size - f->rptr;
94 if (l > len)
95 l = len;
96 memcpy(buf, f->buf + f->rptr, l);
97 f->rptr += l;
98 if (f->rptr >= f->buf_size)
99 f->rptr = 0;
100 buf += l;
101 len -= l;
102 }
103 f->count -= len1;
104 return len1;
105}
106
95219897
PB
107/* ??? This is mis-named.
108 It is used for both text and graphical consoles. */
e7f0ad58
FB
109struct TextConsole {
110 int text_console; /* true if text console */
111 DisplayState *ds;
95219897
PB
112 /* Graphic console state. */
113 vga_hw_update_ptr hw_update;
114 vga_hw_invalidate_ptr hw_invalidate;
115 vga_hw_screen_dump_ptr hw_screen_dump;
116 void *hw;
117
e7f0ad58
FB
118 int g_width, g_height;
119 int width;
120 int height;
121 int total_height;
122 int backscroll_height;
e7f0ad58 123 int x, y;
adb47967 124 int x_saved, y_saved;
e7f0ad58
FB
125 int y_displayed;
126 int y_base;
6d6f7c28
PB
127 TextAttributes t_attrib_default; /* default text attributes */
128 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58
FB
129 TextCell *cells;
130
131 enum TTYState state;
132 int esc_params[MAX_ESC_PARAMS];
133 int nb_esc_params;
134
e5b0bc44 135 CharDriverState *chr;
e15d7371
FB
136 /* fifo for key pressed */
137 QEMUFIFO out_fifo;
138 uint8_t out_fifo_buf[16];
139 QEMUTimer *kbd_timer;
e7f0ad58
FB
140};
141
142static TextConsole *active_console;
143static TextConsole *consoles[MAX_CONSOLES];
144static int nb_consoles = 0;
145
95219897
PB
146void vga_hw_update(void)
147{
adb47967 148 if (active_console && active_console->hw_update)
95219897
PB
149 active_console->hw_update(active_console->hw);
150}
151
152void vga_hw_invalidate(void)
153{
154 if (active_console->hw_invalidate)
155 active_console->hw_invalidate(active_console->hw);
156}
157
158void vga_hw_screen_dump(const char *filename)
159{
160 /* There is currently no was of specifying which screen we want to dump,
161 so always dump the dirst one. */
162 if (consoles[0]->hw_screen_dump)
163 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
164}
165
e7f0ad58
FB
166/* convert a RGBA color to a color index usable in graphic primitives */
167static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
168{
169 unsigned int r, g, b, color;
170
171 switch(ds->depth) {
172#if 0
173 case 8:
174 r = (rgba >> 16) & 0xff;
175 g = (rgba >> 8) & 0xff;
176 b = (rgba) & 0xff;
177 color = (rgb_to_index[r] * 6 * 6) +
178 (rgb_to_index[g] * 6) +
179 (rgb_to_index[b]);
180 break;
181#endif
182 case 15:
183 r = (rgba >> 16) & 0xff;
184 g = (rgba >> 8) & 0xff;
185 b = (rgba) & 0xff;
186 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
187 break;
188 case 16:
189 r = (rgba >> 16) & 0xff;
190 g = (rgba >> 8) & 0xff;
191 b = (rgba) & 0xff;
192 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
193 break;
194 case 32:
195 default:
196 color = rgba;
197 break;
198 }
199 return color;
200}
201
202static void vga_fill_rect (DisplayState *ds,
203 int posx, int posy, int width, int height, uint32_t color)
204{
205 uint8_t *d, *d1;
206 int x, y, bpp;
207
208 bpp = (ds->depth + 7) >> 3;
209 d1 = ds->data +
210 ds->linesize * posy + bpp * posx;
211 for (y = 0; y < height; y++) {
212 d = d1;
213 switch(bpp) {
214 case 1:
215 for (x = 0; x < width; x++) {
216 *((uint8_t *)d) = color;
217 d++;
218 }
219 break;
220 case 2:
221 for (x = 0; x < width; x++) {
222 *((uint16_t *)d) = color;
223 d += 2;
224 }
225 break;
226 case 4:
227 for (x = 0; x < width; x++) {
228 *((uint32_t *)d) = color;
229 d += 4;
230 }
231 break;
232 }
233 d1 += ds->linesize;
234 }
235}
236
237/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
238static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
239{
240 const uint8_t *s;
241 uint8_t *d;
242 int wb, y, bpp;
243
244 bpp = (ds->depth + 7) >> 3;
245 wb = w * bpp;
246 if (yd <= ys) {
247 s = ds->data +
248 ds->linesize * ys + bpp * xs;
249 d = ds->data +
250 ds->linesize * yd + bpp * xd;
251 for (y = 0; y < h; y++) {
252 memmove(d, s, wb);
253 d += ds->linesize;
254 s += ds->linesize;
255 }
256 } else {
257 s = ds->data +
258 ds->linesize * (ys + h - 1) + bpp * xs;
259 d = ds->data +
260 ds->linesize * (yd + h - 1) + bpp * xd;
261 for (y = 0; y < h; y++) {
262 memmove(d, s, wb);
263 d -= ds->linesize;
264 s -= ds->linesize;
265 }
266 }
267}
268
269/***********************************************************/
270/* basic char display */
271
272#define FONT_HEIGHT 16
273#define FONT_WIDTH 8
274
275#include "vgafont.h"
276
277#define cbswap_32(__x) \
278((uint32_t)( \
279 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
280 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
281 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
282 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
283
284#ifdef WORDS_BIGENDIAN
285#define PAT(x) x
286#else
287#define PAT(x) cbswap_32(x)
288#endif
289
290static const uint32_t dmask16[16] = {
291 PAT(0x00000000),
292 PAT(0x000000ff),
293 PAT(0x0000ff00),
294 PAT(0x0000ffff),
295 PAT(0x00ff0000),
296 PAT(0x00ff00ff),
297 PAT(0x00ffff00),
298 PAT(0x00ffffff),
299 PAT(0xff000000),
300 PAT(0xff0000ff),
301 PAT(0xff00ff00),
302 PAT(0xff00ffff),
303 PAT(0xffff0000),
304 PAT(0xffff00ff),
305 PAT(0xffffff00),
306 PAT(0xffffffff),
307};
308
309static const uint32_t dmask4[4] = {
310 PAT(0x00000000),
311 PAT(0x0000ffff),
312 PAT(0xffff0000),
313 PAT(0xffffffff),
314};
315
6d6f7c28
PB
316static uint32_t color_table[2][8];
317
318enum color_names {
319 COLOR_BLACK = 0,
320 COLOR_RED = 1,
321 COLOR_GREEN = 2,
322 COLOR_YELLOW = 3,
323 COLOR_BLUE = 4,
324 COLOR_MAGENTA = 5,
325 COLOR_CYAN = 6,
326 COLOR_WHITE = 7
327};
328
329static const uint32_t color_table_rgb[2][8] = {
330 { /* dark */
26489844
FB
331 QEMU_RGB(0x00, 0x00, 0x00), /* black */
332 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
333 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
334 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
335 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
336 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
337 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
338 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
6d6f7c28
PB
339 },
340 { /* bright */
26489844
FB
341 QEMU_RGB(0x00, 0x00, 0x00), /* black */
342 QEMU_RGB(0xff, 0x00, 0x00), /* red */
343 QEMU_RGB(0x00, 0xff, 0x00), /* green */
344 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
345 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
346 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
347 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
348 QEMU_RGB(0xff, 0xff, 0xff), /* white */
6d6f7c28 349 }
e7f0ad58
FB
350};
351
352static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
353{
354 switch(ds->depth) {
355 case 8:
356 col |= col << 8;
357 col |= col << 16;
358 break;
359 case 15:
360 case 16:
361 col |= col << 16;
362 break;
363 default:
364 break;
365 }
366
367 return col;
368}
6d6f7c28
PB
369#ifdef DEBUG_CONSOLE
370static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
371{
372 if (t_attrib->bold) {
373 printf("b");
374 } else {
375 printf(" ");
376 }
377 if (t_attrib->uline) {
378 printf("u");
379 } else {
380 printf(" ");
381 }
382 if (t_attrib->blink) {
383 printf("l");
384 } else {
385 printf(" ");
386 }
387 if (t_attrib->invers) {
388 printf("i");
389 } else {
390 printf(" ");
391 }
392 if (t_attrib->unvisible) {
393 printf("n");
394 } else {
395 printf(" ");
396 }
397
398 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
399}
400#endif
e7f0ad58
FB
401
402static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 403 TextAttributes *t_attrib)
e7f0ad58
FB
404{
405 uint8_t *d;
406 const uint8_t *font_ptr;
407 unsigned int font_data, linesize, xorcol, bpp;
408 int i;
6d6f7c28
PB
409 unsigned int fgcol, bgcol;
410
411#ifdef DEBUG_CONSOLE
412 printf("x: %2i y: %2i", x, y);
413 console_print_text_attributes(t_attrib, ch);
414#endif
415
416 if (t_attrib->invers) {
417 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
418 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
419 } else {
420 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
421 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
422 }
e7f0ad58
FB
423
424 bpp = (ds->depth + 7) >> 3;
425 d = ds->data +
426 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
427 linesize = ds->linesize;
428 font_ptr = vgafont16 + FONT_HEIGHT * ch;
429 xorcol = bgcol ^ fgcol;
430 switch(ds->depth) {
431 case 8:
432 for(i = 0; i < FONT_HEIGHT; i++) {
433 font_data = *font_ptr++;
6d6f7c28
PB
434 if (t_attrib->uline
435 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
436 font_data = 0xFFFF;
437 }
e7f0ad58
FB
438 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
439 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
440 d += linesize;
441 }
442 break;
443 case 16:
444 case 15:
445 for(i = 0; i < FONT_HEIGHT; i++) {
446 font_data = *font_ptr++;
6d6f7c28
PB
447 if (t_attrib->uline
448 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
449 font_data = 0xFFFF;
450 }
e7f0ad58
FB
451 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
452 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
453 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
454 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
455 d += linesize;
456 }
457 break;
458 case 32:
459 for(i = 0; i < FONT_HEIGHT; i++) {
460 font_data = *font_ptr++;
6d6f7c28
PB
461 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
462 font_data = 0xFFFF;
463 }
e7f0ad58
FB
464 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
465 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
466 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
467 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
468 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
469 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
470 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
471 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
472 d += linesize;
473 }
474 break;
475 }
476}
477
478static void text_console_resize(TextConsole *s)
479{
480 TextCell *cells, *c, *c1;
481 int w1, x, y, last_width;
482
483 last_width = s->width;
484 s->width = s->g_width / FONT_WIDTH;
485 s->height = s->g_height / FONT_HEIGHT;
486
487 w1 = last_width;
488 if (s->width < w1)
489 w1 = s->width;
490
491 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
492 for(y = 0; y < s->total_height; y++) {
493 c = &cells[y * s->width];
494 if (w1 > 0) {
495 c1 = &s->cells[y * last_width];
496 for(x = 0; x < w1; x++) {
497 *c++ = *c1++;
498 }
499 }
500 for(x = w1; x < s->width; x++) {
501 c->ch = ' ';
6d6f7c28 502 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
503 c++;
504 }
505 }
506 free(s->cells);
507 s->cells = cells;
508}
509
510static void update_xy(TextConsole *s, int x, int y)
511{
512 TextCell *c;
513 int y1, y2;
514
515 if (s == active_console) {
516 y1 = (s->y_base + y) % s->total_height;
517 y2 = y1 - s->y_displayed;
518 if (y2 < 0)
519 y2 += s->total_height;
520 if (y2 < s->height) {
521 c = &s->cells[y1 * s->width + x];
522 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 523 &(c->t_attrib));
e7f0ad58
FB
524 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
525 FONT_WIDTH, FONT_HEIGHT);
526 }
527 }
528}
529
530static void console_show_cursor(TextConsole *s, int show)
531{
532 TextCell *c;
533 int y, y1;
534
535 if (s == active_console) {
ed8276ac
TS
536 int x = s->x;
537 if (x >= s->width) {
538 x = s->width - 1;
539 }
e7f0ad58
FB
540 y1 = (s->y_base + s->y) % s->total_height;
541 y = y1 - s->y_displayed;
542 if (y < 0)
543 y += s->total_height;
544 if (y < s->height) {
ed8276ac 545 c = &s->cells[y1 * s->width + x];
e7f0ad58 546 if (show) {
6d6f7c28
PB
547 TextAttributes t_attrib = s->t_attrib_default;
548 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
ed8276ac 549 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
e7f0ad58 550 } else {
ed8276ac 551 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
e7f0ad58 552 }
ed8276ac 553 dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
e7f0ad58
FB
554 FONT_WIDTH, FONT_HEIGHT);
555 }
556 }
557}
558
559static void console_refresh(TextConsole *s)
560{
561 TextCell *c;
562 int x, y, y1;
563
564 if (s != active_console)
565 return;
566
567 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
6d6f7c28 568 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
569 y1 = s->y_displayed;
570 for(y = 0; y < s->height; y++) {
571 c = s->cells + y1 * s->width;
572 for(x = 0; x < s->width; x++) {
573 vga_putcharxy(s->ds, x, y, c->ch,
6d6f7c28 574 &(c->t_attrib));
e7f0ad58
FB
575 c++;
576 }
577 if (++y1 == s->total_height)
578 y1 = 0;
579 }
580 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
581 console_show_cursor(s, 1);
582}
583
584static void console_scroll(int ydelta)
585{
586 TextConsole *s;
587 int i, y1;
588
589 s = active_console;
590 if (!s || !s->text_console)
591 return;
592
593 if (ydelta > 0) {
594 for(i = 0; i < ydelta; i++) {
595 if (s->y_displayed == s->y_base)
596 break;
597 if (++s->y_displayed == s->total_height)
598 s->y_displayed = 0;
599 }
600 } else {
601 ydelta = -ydelta;
602 i = s->backscroll_height;
603 if (i > s->total_height - s->height)
604 i = s->total_height - s->height;
605 y1 = s->y_base - i;
606 if (y1 < 0)
607 y1 += s->total_height;
608 for(i = 0; i < ydelta; i++) {
609 if (s->y_displayed == y1)
610 break;
611 if (--s->y_displayed < 0)
612 s->y_displayed = s->total_height - 1;
613 }
614 }
615 console_refresh(s);
616}
617
618static void console_put_lf(TextConsole *s)
619{
620 TextCell *c;
621 int x, y1;
622
e7f0ad58
FB
623 s->y++;
624 if (s->y >= s->height) {
625 s->y = s->height - 1;
6d6f7c28 626
e7f0ad58
FB
627 if (s->y_displayed == s->y_base) {
628 if (++s->y_displayed == s->total_height)
629 s->y_displayed = 0;
630 }
631 if (++s->y_base == s->total_height)
632 s->y_base = 0;
633 if (s->backscroll_height < s->total_height)
634 s->backscroll_height++;
635 y1 = (s->y_base + s->height - 1) % s->total_height;
636 c = &s->cells[y1 * s->width];
637 for(x = 0; x < s->width; x++) {
638 c->ch = ' ';
6d6f7c28 639 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
640 c++;
641 }
642 if (s == active_console && s->y_displayed == s->y_base) {
643 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
644 s->width * FONT_WIDTH,
645 (s->height - 1) * FONT_HEIGHT);
646 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
647 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 648 color_table[0][s->t_attrib_default.bgcol]);
e7f0ad58
FB
649 dpy_update(s->ds, 0, 0,
650 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
651 }
652 }
653}
654
6d6f7c28
PB
655/* Set console attributes depending on the current escape codes.
656 * NOTE: I know this code is not very efficient (checking every color for it
657 * self) but it is more readable and better maintainable.
658 */
659static void console_handle_escape(TextConsole *s)
660{
661 int i;
662
6d6f7c28
PB
663 for (i=0; i<s->nb_esc_params; i++) {
664 switch (s->esc_params[i]) {
665 case 0: /* reset all console attributes to default */
666 s->t_attrib = s->t_attrib_default;
667 break;
668 case 1:
669 s->t_attrib.bold = 1;
670 break;
671 case 4:
672 s->t_attrib.uline = 1;
673 break;
674 case 5:
675 s->t_attrib.blink = 1;
676 break;
677 case 7:
678 s->t_attrib.invers = 1;
679 break;
680 case 8:
681 s->t_attrib.unvisible = 1;
682 break;
683 case 22:
684 s->t_attrib.bold = 0;
685 break;
686 case 24:
687 s->t_attrib.uline = 0;
688 break;
689 case 25:
690 s->t_attrib.blink = 0;
691 break;
692 case 27:
693 s->t_attrib.invers = 0;
694 break;
695 case 28:
696 s->t_attrib.unvisible = 0;
697 break;
698 /* set foreground color */
699 case 30:
700 s->t_attrib.fgcol=COLOR_BLACK;
701 break;
702 case 31:
703 s->t_attrib.fgcol=COLOR_RED;
704 break;
705 case 32:
706 s->t_attrib.fgcol=COLOR_GREEN;
707 break;
708 case 33:
709 s->t_attrib.fgcol=COLOR_YELLOW;
710 break;
711 case 34:
712 s->t_attrib.fgcol=COLOR_BLUE;
713 break;
714 case 35:
715 s->t_attrib.fgcol=COLOR_MAGENTA;
716 break;
717 case 36:
718 s->t_attrib.fgcol=COLOR_CYAN;
719 break;
720 case 37:
721 s->t_attrib.fgcol=COLOR_WHITE;
722 break;
723 /* set background color */
724 case 40:
725 s->t_attrib.bgcol=COLOR_BLACK;
726 break;
727 case 41:
728 s->t_attrib.bgcol=COLOR_RED;
729 break;
730 case 42:
731 s->t_attrib.bgcol=COLOR_GREEN;
732 break;
733 case 43:
734 s->t_attrib.bgcol=COLOR_YELLOW;
735 break;
736 case 44:
737 s->t_attrib.bgcol=COLOR_BLUE;
738 break;
739 case 45:
740 s->t_attrib.bgcol=COLOR_MAGENTA;
741 break;
742 case 46:
743 s->t_attrib.bgcol=COLOR_CYAN;
744 break;
745 case 47:
746 s->t_attrib.bgcol=COLOR_WHITE;
747 break;
748 }
749 }
750}
751
adb47967
TS
752static void console_clear_xy(TextConsole *s, int x, int y)
753{
754 int y1 = (s->y_base + y) % s->total_height;
755 TextCell *c = &s->cells[y1 * s->width + x];
756 c->ch = ' ';
757 c->t_attrib = s->t_attrib_default;
758 c++;
759 update_xy(s, x, y);
760}
761
e7f0ad58
FB
762static void console_putchar(TextConsole *s, int ch)
763{
764 TextCell *c;
adb47967
TS
765 int y1, i;
766 int x, y;
e7f0ad58
FB
767
768 switch(s->state) {
769 case TTY_STATE_NORM:
770 switch(ch) {
6d6f7c28 771 case '\r': /* carriage return */
e7f0ad58
FB
772 s->x = 0;
773 break;
6d6f7c28 774 case '\n': /* newline */
e7f0ad58
FB
775 console_put_lf(s);
776 break;
6d6f7c28 777 case '\b': /* backspace */
e15d7371
FB
778 if (s->x > 0)
779 s->x--;
6d6f7c28
PB
780 break;
781 case '\t': /* tabspace */
782 if (s->x + (8 - (s->x % 8)) > s->width) {
bd468840 783 s->x = 0;
6d6f7c28
PB
784 console_put_lf(s);
785 } else {
786 s->x = s->x + (8 - (s->x % 8));
787 }
788 break;
789 case '\a': /* alert aka. bell */
790 /* TODO: has to be implemented */
791 break;
adb47967
TS
792 case 14:
793 /* SI (shift in), character set 0 (ignored) */
794 break;
795 case 15:
796 /* SO (shift out), character set 1 (ignored) */
797 break;
6d6f7c28 798 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
799 s->state = TTY_STATE_ESC;
800 break;
801 default:
ed8276ac
TS
802 if (s->x >= s->width) {
803 /* line wrap */
804 s->x = 0;
805 console_put_lf(s);
adb47967 806 }
e7f0ad58
FB
807 y1 = (s->y_base + s->y) % s->total_height;
808 c = &s->cells[y1 * s->width + s->x];
809 c->ch = ch;
6d6f7c28 810 c->t_attrib = s->t_attrib;
e7f0ad58
FB
811 update_xy(s, s->x, s->y);
812 s->x++;
e7f0ad58
FB
813 break;
814 }
815 break;
6d6f7c28 816 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
817 if (ch == '[') {
818 for(i=0;i<MAX_ESC_PARAMS;i++)
819 s->esc_params[i] = 0;
820 s->nb_esc_params = 0;
821 s->state = TTY_STATE_CSI;
822 } else {
823 s->state = TTY_STATE_NORM;
824 }
825 break;
6d6f7c28 826 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
827 if (ch >= '0' && ch <= '9') {
828 if (s->nb_esc_params < MAX_ESC_PARAMS) {
829 s->esc_params[s->nb_esc_params] =
830 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
831 }
832 } else {
833 s->nb_esc_params++;
834 if (ch == ';')
835 break;
adb47967
TS
836#ifdef DEBUG_CONSOLE
837 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
838 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
839#endif
e7f0ad58
FB
840 s->state = TTY_STATE_NORM;
841 switch(ch) {
adb47967
TS
842 case 'A':
843 /* move cursor up */
844 if (s->esc_params[0] == 0) {
845 s->esc_params[0] = 1;
846 }
847 s->y -= s->esc_params[0];
848 if (s->y < 0) {
849 s->y = 0;
850 }
851 break;
852 case 'B':
853 /* move cursor down */
854 if (s->esc_params[0] == 0) {
855 s->esc_params[0] = 1;
856 }
857 s->y += s->esc_params[0];
858 if (s->y >= s->height) {
859 s->y = s->height - 1;
860 }
e7f0ad58
FB
861 break;
862 case 'C':
adb47967
TS
863 /* move cursor right */
864 if (s->esc_params[0] == 0) {
865 s->esc_params[0] = 1;
866 }
867 s->x += s->esc_params[0];
868 if (s->x >= s->width) {
869 s->x = s->width - 1;
870 }
e7f0ad58 871 break;
adb47967
TS
872 case 'D':
873 /* move cursor left */
874 if (s->esc_params[0] == 0) {
875 s->esc_params[0] = 1;
876 }
877 s->x -= s->esc_params[0];
878 if (s->x < 0) {
879 s->x = 0;
880 }
881 break;
882 case 'G':
883 /* move cursor to column */
884 s->x = s->esc_params[0] - 1;
885 if (s->x < 0) {
886 s->x = 0;
887 }
888 break;
889 case 'f':
890 case 'H':
891 /* move cursor to row, column */
892 s->x = s->esc_params[1] - 1;
893 if (s->x < 0) {
894 s->x = 0;
895 }
896 s->y = s->esc_params[0] - 1;
897 if (s->y < 0) {
898 s->y = 0;
899 }
900 break;
901 case 'J':
902 switch (s->esc_params[0]) {
903 case 0:
904 /* clear to end of screen */
905 for (y = s->y; y < s->height; y++) {
906 for (x = 0; x < s->width; x++) {
907 if (y == s->y && x < s->x) {
908 continue;
909 }
910 console_clear_xy(s, x, y);
911 }
912 }
913 break;
914 case 1:
915 /* clear from beginning of screen */
916 for (y = 0; y <= s->y; y++) {
917 for (x = 0; x < s->width; x++) {
918 if (y == s->y && x > s->x) {
919 break;
920 }
921 console_clear_xy(s, x, y);
922 }
923 }
924 break;
925 case 2:
926 /* clear entire screen */
927 for (y = 0; y <= s->height; y++) {
928 for (x = 0; x < s->width; x++) {
929 console_clear_xy(s, x, y);
930 }
931 }
932 break;
933 }
e7f0ad58 934 case 'K':
adb47967
TS
935 switch (s->esc_params[0]) {
936 case 0:
e7f0ad58 937 /* clear to eol */
e7f0ad58 938 for(x = s->x; x < s->width; x++) {
adb47967 939 console_clear_xy(s, x, s->y);
e7f0ad58
FB
940 }
941 break;
adb47967
TS
942 case 1:
943 /* clear from beginning of line */
944 for (x = 0; x <= s->x; x++) {
945 console_clear_xy(s, x, s->y);
946 }
947 break;
948 case 2:
949 /* clear entire line */
950 for(x = 0; x < s->width; x++) {
951 console_clear_xy(s, x, s->y);
952 }
e7f0ad58
FB
953 break;
954 }
adb47967
TS
955 break;
956 case 'm':
6d6f7c28 957 console_handle_escape(s);
e7f0ad58 958 break;
adb47967
TS
959 case 'n':
960 /* report cursor position */
961 /* TODO: send ESC[row;colR */
962 break;
963 case 's':
964 /* save cursor position */
965 s->x_saved = s->x;
966 s->y_saved = s->y;
967 break;
968 case 'u':
969 /* restore cursor position */
970 s->x = s->x_saved;
971 s->y = s->y_saved;
972 break;
973 default:
974#ifdef DEBUG_CONSOLE
975 fprintf(stderr, "unhandled escape character '%c'\n", ch);
976#endif
977 break;
978 }
979 break;
e7f0ad58
FB
980 }
981 }
982}
983
984void console_select(unsigned int index)
985{
986 TextConsole *s;
6d6f7c28 987
e7f0ad58
FB
988 if (index >= MAX_CONSOLES)
989 return;
990 s = consoles[index];
991 if (s) {
992 active_console = s;
993 if (s->text_console) {
994 if (s->g_width != s->ds->width ||
8e3a9fd2 995 s->g_height != s->ds->height) {
6d6f7c28
PB
996 s->g_width = s->ds->width;
997 s->g_height = s->ds->height;
e7f0ad58 998 text_console_resize(s);
95219897 999 }
e7f0ad58 1000 console_refresh(s);
95219897
PB
1001 } else {
1002 vga_hw_invalidate();
e7f0ad58
FB
1003 }
1004 }
1005}
1006
1007static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1008{
1009 TextConsole *s = chr->opaque;
1010 int i;
1011
1012 console_show_cursor(s, 0);
1013 for(i = 0; i < len; i++) {
1014 console_putchar(s, buf[i]);
1015 }
1016 console_show_cursor(s, 1);
1017 return len;
1018}
1019
6fcfafb7
FB
1020static void console_send_event(CharDriverState *chr, int event)
1021{
1022 TextConsole *s = chr->opaque;
1023 int i;
1024
1025 if (event == CHR_EVENT_FOCUS) {
1026 for(i = 0; i < nb_consoles; i++) {
1027 if (consoles[i] == s) {
1028 console_select(i);
1029 break;
1030 }
1031 }
1032 }
1033}
1034
e15d7371
FB
1035static void kbd_send_chars(void *opaque)
1036{
1037 TextConsole *s = opaque;
1038 int len;
1039 uint8_t buf[16];
1040
e5b0bc44 1041 len = qemu_chr_can_read(s->chr);
e15d7371
FB
1042 if (len > s->out_fifo.count)
1043 len = s->out_fifo.count;
1044 if (len > 0) {
1045 if (len > sizeof(buf))
1046 len = sizeof(buf);
1047 qemu_fifo_read(&s->out_fifo, buf, len);
e5b0bc44 1048 qemu_chr_read(s->chr, buf, len);
e15d7371
FB
1049 }
1050 /* characters are pending: we send them a bit later (XXX:
1051 horrible, should change char device API) */
1052 if (s->out_fifo.count > 0) {
1053 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1054 }
1055}
1056
e7f0ad58
FB
1057/* called when an ascii key is pressed */
1058void kbd_put_keysym(int keysym)
1059{
1060 TextConsole *s;
1061 uint8_t buf[16], *q;
1062 int c;
1063
1064 s = active_console;
1065 if (!s || !s->text_console)
1066 return;
1067
1068 switch(keysym) {
1069 case QEMU_KEY_CTRL_UP:
1070 console_scroll(-1);
1071 break;
1072 case QEMU_KEY_CTRL_DOWN:
1073 console_scroll(1);
1074 break;
1075 case QEMU_KEY_CTRL_PAGEUP:
1076 console_scroll(-10);
1077 break;
1078 case QEMU_KEY_CTRL_PAGEDOWN:
1079 console_scroll(10);
1080 break;
1081 default:
e15d7371
FB
1082 /* convert the QEMU keysym to VT100 key string */
1083 q = buf;
1084 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1085 *q++ = '\033';
1086 *q++ = '[';
1087 c = keysym - 0xe100;
1088 if (c >= 10)
1089 *q++ = '0' + (c / 10);
1090 *q++ = '0' + (c % 10);
1091 *q++ = '~';
1092 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1093 *q++ = '\033';
1094 *q++ = '[';
1095 *q++ = keysym & 0xff;
1096 } else {
e7f0ad58 1097 *q++ = keysym;
e15d7371 1098 }
e5b0bc44 1099 if (s->chr->chr_read) {
e15d7371
FB
1100 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1101 kbd_send_chars(s);
e7f0ad58
FB
1102 }
1103 break;
1104 }
1105}
1106
95219897 1107static TextConsole *new_console(DisplayState *ds, int text)
e7f0ad58
FB
1108{
1109 TextConsole *s;
95219897 1110 int i;
e7f0ad58
FB
1111
1112 if (nb_consoles >= MAX_CONSOLES)
1113 return NULL;
1114 s = qemu_mallocz(sizeof(TextConsole));
1115 if (!s) {
1116 return NULL;
1117 }
95219897 1118 if (!active_console || (active_console->text_console && !text))
e7f0ad58
FB
1119 active_console = s;
1120 s->ds = ds;
95219897
PB
1121 s->text_console = text;
1122 if (text) {
1123 consoles[nb_consoles++] = s;
1124 } else {
1125 /* HACK: Put graphical consoles before text consoles. */
1126 for (i = nb_consoles; i > 0; i--) {
1127 if (!consoles[i - 1]->text_console)
1128 break;
1129 consoles[i] = consoles[i - 1];
1130 }
1131 consoles[i] = s;
1132 }
1133 return s;
1134}
1135
1136TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1137 vga_hw_invalidate_ptr invalidate,
1138 vga_hw_screen_dump_ptr screen_dump,
1139 void *opaque)
1140{
1141 TextConsole *s;
1142
1143 s = new_console(ds, 0);
1144 if (!s)
1145 return NULL;
1146 s->hw_update = update;
1147 s->hw_invalidate = invalidate;
1148 s->hw_screen_dump = screen_dump;
1149 s->hw = opaque;
e7f0ad58
FB
1150 return s;
1151}
1152
95219897 1153int is_graphic_console(void)
e7f0ad58 1154{
95219897 1155 return !active_console->text_console;
e7f0ad58
FB
1156}
1157
1158CharDriverState *text_console_init(DisplayState *ds)
1159{
1160 CharDriverState *chr;
1161 TextConsole *s;
6d6f7c28 1162 int i,j;
e7f0ad58 1163 static int color_inited;
6d6f7c28 1164
e7f0ad58
FB
1165 chr = qemu_mallocz(sizeof(CharDriverState));
1166 if (!chr)
1167 return NULL;
95219897 1168 s = new_console(ds, 1);
e7f0ad58
FB
1169 if (!s) {
1170 free(chr);
1171 return NULL;
1172 }
e7f0ad58
FB
1173 chr->opaque = s;
1174 chr->chr_write = console_puts;
6fcfafb7
FB
1175 chr->chr_send_event = console_send_event;
1176
e5b0bc44 1177 s->chr = chr;
e15d7371
FB
1178 s->out_fifo.buf = s->out_fifo_buf;
1179 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1180 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1181
e7f0ad58
FB
1182 if (!color_inited) {
1183 color_inited = 1;
6d6f7c28
PB
1184 for(j = 0; j < 2; j++) {
1185 for(i = 0; i < 8; i++) {
1186 color_table[j][i] = col_expand(s->ds,
1187 vga_get_color(s->ds, color_table_rgb[j][i]));
1188 }
e7f0ad58
FB
1189 }
1190 }
1191 s->y_displayed = 0;
1192 s->y_base = 0;
1193 s->total_height = DEFAULT_BACKSCROLL;
1194 s->x = 0;
1195 s->y = 0;
e7f0ad58
FB
1196 s->g_width = s->ds->width;
1197 s->g_height = s->ds->height;
6d6f7c28
PB
1198
1199 /* Set text attribute defaults */
1200 s->t_attrib_default.bold = 0;
1201 s->t_attrib_default.uline = 0;
1202 s->t_attrib_default.blink = 0;
1203 s->t_attrib_default.invers = 0;
1204 s->t_attrib_default.unvisible = 0;
1205 s->t_attrib_default.fgcol = COLOR_WHITE;
1206 s->t_attrib_default.bgcol = COLOR_BLACK;
1207
1208 /* set current text attributes to default */
1209 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1210 text_console_resize(s);
1211
86e94dea
TS
1212 qemu_chr_reset(chr);
1213
e7f0ad58
FB
1214 return chr;
1215}