]> git.proxmox.com Git - qemu.git/blame - console.c
update
[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
FB
123 int x, y;
124 int y_displayed;
125 int y_base;
6d6f7c28
PB
126 TextAttributes t_attrib_default; /* default text attributes */
127 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58
FB
128 TextCell *cells;
129
130 enum TTYState state;
131 int esc_params[MAX_ESC_PARAMS];
132 int nb_esc_params;
133
134 /* kbd read handler */
e15d7371 135 IOCanRWHandler *fd_can_read;
e7f0ad58
FB
136 IOReadHandler *fd_read;
137 void *fd_opaque;
e15d7371
FB
138 /* fifo for key pressed */
139 QEMUFIFO out_fifo;
140 uint8_t out_fifo_buf[16];
141 QEMUTimer *kbd_timer;
e7f0ad58
FB
142};
143
144static TextConsole *active_console;
145static TextConsole *consoles[MAX_CONSOLES];
146static int nb_consoles = 0;
147
95219897
PB
148void vga_hw_update(void)
149{
150 if (active_console->hw_update)
151 active_console->hw_update(active_console->hw);
152}
153
154void vga_hw_invalidate(void)
155{
156 if (active_console->hw_invalidate)
157 active_console->hw_invalidate(active_console->hw);
158}
159
160void vga_hw_screen_dump(const char *filename)
161{
162 /* There is currently no was of specifying which screen we want to dump,
163 so always dump the dirst one. */
164 if (consoles[0]->hw_screen_dump)
165 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
166}
167
e7f0ad58
FB
168/* convert a RGBA color to a color index usable in graphic primitives */
169static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
170{
171 unsigned int r, g, b, color;
172
173 switch(ds->depth) {
174#if 0
175 case 8:
176 r = (rgba >> 16) & 0xff;
177 g = (rgba >> 8) & 0xff;
178 b = (rgba) & 0xff;
179 color = (rgb_to_index[r] * 6 * 6) +
180 (rgb_to_index[g] * 6) +
181 (rgb_to_index[b]);
182 break;
183#endif
184 case 15:
185 r = (rgba >> 16) & 0xff;
186 g = (rgba >> 8) & 0xff;
187 b = (rgba) & 0xff;
188 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
189 break;
190 case 16:
191 r = (rgba >> 16) & 0xff;
192 g = (rgba >> 8) & 0xff;
193 b = (rgba) & 0xff;
194 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
195 break;
196 case 32:
197 default:
198 color = rgba;
199 break;
200 }
201 return color;
202}
203
204static void vga_fill_rect (DisplayState *ds,
205 int posx, int posy, int width, int height, uint32_t color)
206{
207 uint8_t *d, *d1;
208 int x, y, bpp;
209
210 bpp = (ds->depth + 7) >> 3;
211 d1 = ds->data +
212 ds->linesize * posy + bpp * posx;
213 for (y = 0; y < height; y++) {
214 d = d1;
215 switch(bpp) {
216 case 1:
217 for (x = 0; x < width; x++) {
218 *((uint8_t *)d) = color;
219 d++;
220 }
221 break;
222 case 2:
223 for (x = 0; x < width; x++) {
224 *((uint16_t *)d) = color;
225 d += 2;
226 }
227 break;
228 case 4:
229 for (x = 0; x < width; x++) {
230 *((uint32_t *)d) = color;
231 d += 4;
232 }
233 break;
234 }
235 d1 += ds->linesize;
236 }
237}
238
239/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
240static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
241{
242 const uint8_t *s;
243 uint8_t *d;
244 int wb, y, bpp;
245
246 bpp = (ds->depth + 7) >> 3;
247 wb = w * bpp;
248 if (yd <= ys) {
249 s = ds->data +
250 ds->linesize * ys + bpp * xs;
251 d = ds->data +
252 ds->linesize * yd + bpp * xd;
253 for (y = 0; y < h; y++) {
254 memmove(d, s, wb);
255 d += ds->linesize;
256 s += ds->linesize;
257 }
258 } else {
259 s = ds->data +
260 ds->linesize * (ys + h - 1) + bpp * xs;
261 d = ds->data +
262 ds->linesize * (yd + h - 1) + bpp * xd;
263 for (y = 0; y < h; y++) {
264 memmove(d, s, wb);
265 d -= ds->linesize;
266 s -= ds->linesize;
267 }
268 }
269}
270
271/***********************************************************/
272/* basic char display */
273
274#define FONT_HEIGHT 16
275#define FONT_WIDTH 8
276
277#include "vgafont.h"
278
279#define cbswap_32(__x) \
280((uint32_t)( \
281 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
282 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
283 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
284 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
285
286#ifdef WORDS_BIGENDIAN
287#define PAT(x) x
288#else
289#define PAT(x) cbswap_32(x)
290#endif
291
292static const uint32_t dmask16[16] = {
293 PAT(0x00000000),
294 PAT(0x000000ff),
295 PAT(0x0000ff00),
296 PAT(0x0000ffff),
297 PAT(0x00ff0000),
298 PAT(0x00ff00ff),
299 PAT(0x00ffff00),
300 PAT(0x00ffffff),
301 PAT(0xff000000),
302 PAT(0xff0000ff),
303 PAT(0xff00ff00),
304 PAT(0xff00ffff),
305 PAT(0xffff0000),
306 PAT(0xffff00ff),
307 PAT(0xffffff00),
308 PAT(0xffffffff),
309};
310
311static const uint32_t dmask4[4] = {
312 PAT(0x00000000),
313 PAT(0x0000ffff),
314 PAT(0xffff0000),
315 PAT(0xffffffff),
316};
317
6d6f7c28
PB
318static uint32_t color_table[2][8];
319
320enum color_names {
321 COLOR_BLACK = 0,
322 COLOR_RED = 1,
323 COLOR_GREEN = 2,
324 COLOR_YELLOW = 3,
325 COLOR_BLUE = 4,
326 COLOR_MAGENTA = 5,
327 COLOR_CYAN = 6,
328 COLOR_WHITE = 7
329};
330
331static const uint32_t color_table_rgb[2][8] = {
332 { /* dark */
26489844
FB
333 QEMU_RGB(0x00, 0x00, 0x00), /* black */
334 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
335 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
336 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
337 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
338 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
339 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
340 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
6d6f7c28
PB
341 },
342 { /* bright */
26489844
FB
343 QEMU_RGB(0x00, 0x00, 0x00), /* black */
344 QEMU_RGB(0xff, 0x00, 0x00), /* red */
345 QEMU_RGB(0x00, 0xff, 0x00), /* green */
346 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
347 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
348 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
349 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
350 QEMU_RGB(0xff, 0xff, 0xff), /* white */
6d6f7c28 351 }
e7f0ad58
FB
352};
353
354static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
355{
356 switch(ds->depth) {
357 case 8:
358 col |= col << 8;
359 col |= col << 16;
360 break;
361 case 15:
362 case 16:
363 col |= col << 16;
364 break;
365 default:
366 break;
367 }
368
369 return col;
370}
6d6f7c28
PB
371#ifdef DEBUG_CONSOLE
372static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
373{
374 if (t_attrib->bold) {
375 printf("b");
376 } else {
377 printf(" ");
378 }
379 if (t_attrib->uline) {
380 printf("u");
381 } else {
382 printf(" ");
383 }
384 if (t_attrib->blink) {
385 printf("l");
386 } else {
387 printf(" ");
388 }
389 if (t_attrib->invers) {
390 printf("i");
391 } else {
392 printf(" ");
393 }
394 if (t_attrib->unvisible) {
395 printf("n");
396 } else {
397 printf(" ");
398 }
399
400 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
401}
402#endif
e7f0ad58
FB
403
404static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 405 TextAttributes *t_attrib)
e7f0ad58
FB
406{
407 uint8_t *d;
408 const uint8_t *font_ptr;
409 unsigned int font_data, linesize, xorcol, bpp;
410 int i;
6d6f7c28
PB
411 unsigned int fgcol, bgcol;
412
413#ifdef DEBUG_CONSOLE
414 printf("x: %2i y: %2i", x, y);
415 console_print_text_attributes(t_attrib, ch);
416#endif
417
418 if (t_attrib->invers) {
419 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
420 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
421 } else {
422 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
423 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
424 }
e7f0ad58
FB
425
426 bpp = (ds->depth + 7) >> 3;
427 d = ds->data +
428 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
429 linesize = ds->linesize;
430 font_ptr = vgafont16 + FONT_HEIGHT * ch;
431 xorcol = bgcol ^ fgcol;
432 switch(ds->depth) {
433 case 8:
434 for(i = 0; i < FONT_HEIGHT; i++) {
435 font_data = *font_ptr++;
6d6f7c28
PB
436 if (t_attrib->uline
437 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
438 font_data = 0xFFFF;
439 }
e7f0ad58
FB
440 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
441 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
442 d += linesize;
443 }
444 break;
445 case 16:
446 case 15:
447 for(i = 0; i < FONT_HEIGHT; i++) {
448 font_data = *font_ptr++;
6d6f7c28
PB
449 if (t_attrib->uline
450 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
451 font_data = 0xFFFF;
452 }
e7f0ad58
FB
453 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
454 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
455 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
456 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
457 d += linesize;
458 }
459 break;
460 case 32:
461 for(i = 0; i < FONT_HEIGHT; i++) {
462 font_data = *font_ptr++;
6d6f7c28
PB
463 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
464 font_data = 0xFFFF;
465 }
e7f0ad58
FB
466 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
467 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
468 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
469 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
470 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
471 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
472 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
473 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
474 d += linesize;
475 }
476 break;
477 }
478}
479
480static void text_console_resize(TextConsole *s)
481{
482 TextCell *cells, *c, *c1;
483 int w1, x, y, last_width;
484
485 last_width = s->width;
486 s->width = s->g_width / FONT_WIDTH;
487 s->height = s->g_height / FONT_HEIGHT;
488
489 w1 = last_width;
490 if (s->width < w1)
491 w1 = s->width;
492
493 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
494 for(y = 0; y < s->total_height; y++) {
495 c = &cells[y * s->width];
496 if (w1 > 0) {
497 c1 = &s->cells[y * last_width];
498 for(x = 0; x < w1; x++) {
499 *c++ = *c1++;
500 }
501 }
502 for(x = w1; x < s->width; x++) {
503 c->ch = ' ';
6d6f7c28 504 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
505 c++;
506 }
507 }
508 free(s->cells);
509 s->cells = cells;
510}
511
512static void update_xy(TextConsole *s, int x, int y)
513{
514 TextCell *c;
515 int y1, y2;
516
517 if (s == active_console) {
518 y1 = (s->y_base + y) % s->total_height;
519 y2 = y1 - s->y_displayed;
520 if (y2 < 0)
521 y2 += s->total_height;
522 if (y2 < s->height) {
523 c = &s->cells[y1 * s->width + x];
524 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 525 &(c->t_attrib));
e7f0ad58
FB
526 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
527 FONT_WIDTH, FONT_HEIGHT);
528 }
529 }
530}
531
532static void console_show_cursor(TextConsole *s, int show)
533{
534 TextCell *c;
535 int y, y1;
536
537 if (s == active_console) {
538 y1 = (s->y_base + s->y) % s->total_height;
539 y = y1 - s->y_displayed;
540 if (y < 0)
541 y += s->total_height;
542 if (y < s->height) {
543 c = &s->cells[y1 * s->width + s->x];
544 if (show) {
6d6f7c28
PB
545 TextAttributes t_attrib = s->t_attrib_default;
546 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
547 vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
e7f0ad58
FB
548 } else {
549 vga_putcharxy(s->ds, s->x, y, c->ch,
6d6f7c28 550 &(c->t_attrib));
e7f0ad58
FB
551 }
552 dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
553 FONT_WIDTH, FONT_HEIGHT);
554 }
555 }
556}
557
558static void console_refresh(TextConsole *s)
559{
560 TextCell *c;
561 int x, y, y1;
562
563 if (s != active_console)
564 return;
565
566 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
6d6f7c28 567 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
568 y1 = s->y_displayed;
569 for(y = 0; y < s->height; y++) {
570 c = s->cells + y1 * s->width;
571 for(x = 0; x < s->width; x++) {
572 vga_putcharxy(s->ds, x, y, c->ch,
6d6f7c28 573 &(c->t_attrib));
e7f0ad58
FB
574 c++;
575 }
576 if (++y1 == s->total_height)
577 y1 = 0;
578 }
579 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
580 console_show_cursor(s, 1);
581}
582
583static void console_scroll(int ydelta)
584{
585 TextConsole *s;
586 int i, y1;
587
588 s = active_console;
589 if (!s || !s->text_console)
590 return;
591
592 if (ydelta > 0) {
593 for(i = 0; i < ydelta; i++) {
594 if (s->y_displayed == s->y_base)
595 break;
596 if (++s->y_displayed == s->total_height)
597 s->y_displayed = 0;
598 }
599 } else {
600 ydelta = -ydelta;
601 i = s->backscroll_height;
602 if (i > s->total_height - s->height)
603 i = s->total_height - s->height;
604 y1 = s->y_base - i;
605 if (y1 < 0)
606 y1 += s->total_height;
607 for(i = 0; i < ydelta; i++) {
608 if (s->y_displayed == y1)
609 break;
610 if (--s->y_displayed < 0)
611 s->y_displayed = s->total_height - 1;
612 }
613 }
614 console_refresh(s);
615}
616
617static void console_put_lf(TextConsole *s)
618{
619 TextCell *c;
620 int x, y1;
621
622 s->x = 0;
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
663 if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
664 s->t_attrib = s->t_attrib_default;
665 return;
666 }
667 for (i=0; i<s->nb_esc_params; i++) {
668 switch (s->esc_params[i]) {
669 case 0: /* reset all console attributes to default */
670 s->t_attrib = s->t_attrib_default;
671 break;
672 case 1:
673 s->t_attrib.bold = 1;
674 break;
675 case 4:
676 s->t_attrib.uline = 1;
677 break;
678 case 5:
679 s->t_attrib.blink = 1;
680 break;
681 case 7:
682 s->t_attrib.invers = 1;
683 break;
684 case 8:
685 s->t_attrib.unvisible = 1;
686 break;
687 case 22:
688 s->t_attrib.bold = 0;
689 break;
690 case 24:
691 s->t_attrib.uline = 0;
692 break;
693 case 25:
694 s->t_attrib.blink = 0;
695 break;
696 case 27:
697 s->t_attrib.invers = 0;
698 break;
699 case 28:
700 s->t_attrib.unvisible = 0;
701 break;
702 /* set foreground color */
703 case 30:
704 s->t_attrib.fgcol=COLOR_BLACK;
705 break;
706 case 31:
707 s->t_attrib.fgcol=COLOR_RED;
708 break;
709 case 32:
710 s->t_attrib.fgcol=COLOR_GREEN;
711 break;
712 case 33:
713 s->t_attrib.fgcol=COLOR_YELLOW;
714 break;
715 case 34:
716 s->t_attrib.fgcol=COLOR_BLUE;
717 break;
718 case 35:
719 s->t_attrib.fgcol=COLOR_MAGENTA;
720 break;
721 case 36:
722 s->t_attrib.fgcol=COLOR_CYAN;
723 break;
724 case 37:
725 s->t_attrib.fgcol=COLOR_WHITE;
726 break;
727 /* set background color */
728 case 40:
729 s->t_attrib.bgcol=COLOR_BLACK;
730 break;
731 case 41:
732 s->t_attrib.bgcol=COLOR_RED;
733 break;
734 case 42:
735 s->t_attrib.bgcol=COLOR_GREEN;
736 break;
737 case 43:
738 s->t_attrib.bgcol=COLOR_YELLOW;
739 break;
740 case 44:
741 s->t_attrib.bgcol=COLOR_BLUE;
742 break;
743 case 45:
744 s->t_attrib.bgcol=COLOR_MAGENTA;
745 break;
746 case 46:
747 s->t_attrib.bgcol=COLOR_CYAN;
748 break;
749 case 47:
750 s->t_attrib.bgcol=COLOR_WHITE;
751 break;
752 }
753 }
754}
755
e7f0ad58
FB
756static void console_putchar(TextConsole *s, int ch)
757{
758 TextCell *c;
759 int y1, i, x;
760
761 switch(s->state) {
762 case TTY_STATE_NORM:
763 switch(ch) {
6d6f7c28 764 case '\r': /* carriage return */
e7f0ad58
FB
765 s->x = 0;
766 break;
6d6f7c28 767 case '\n': /* newline */
e7f0ad58
FB
768 console_put_lf(s);
769 break;
6d6f7c28 770 case '\b': /* backspace */
e15d7371
FB
771 if (s->x > 0)
772 s->x--;
6d6f7c28
PB
773 break;
774 case '\t': /* tabspace */
775 if (s->x + (8 - (s->x % 8)) > s->width) {
776 console_put_lf(s);
777 } else {
778 s->x = s->x + (8 - (s->x % 8));
779 }
780 break;
781 case '\a': /* alert aka. bell */
782 /* TODO: has to be implemented */
783 break;
784 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
785 s->state = TTY_STATE_ESC;
786 break;
787 default:
788 y1 = (s->y_base + s->y) % s->total_height;
789 c = &s->cells[y1 * s->width + s->x];
790 c->ch = ch;
6d6f7c28 791 c->t_attrib = s->t_attrib;
e7f0ad58
FB
792 update_xy(s, s->x, s->y);
793 s->x++;
794 if (s->x >= s->width)
795 console_put_lf(s);
796 break;
797 }
798 break;
6d6f7c28 799 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
800 if (ch == '[') {
801 for(i=0;i<MAX_ESC_PARAMS;i++)
802 s->esc_params[i] = 0;
803 s->nb_esc_params = 0;
804 s->state = TTY_STATE_CSI;
805 } else {
806 s->state = TTY_STATE_NORM;
807 }
808 break;
6d6f7c28 809 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
810 if (ch >= '0' && ch <= '9') {
811 if (s->nb_esc_params < MAX_ESC_PARAMS) {
812 s->esc_params[s->nb_esc_params] =
813 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
814 }
815 } else {
816 s->nb_esc_params++;
817 if (ch == ';')
818 break;
819 s->state = TTY_STATE_NORM;
820 switch(ch) {
821 case 'D':
822 if (s->x > 0)
823 s->x--;
824 break;
825 case 'C':
826 if (s->x < (s->width - 1))
827 s->x++;
828 break;
829 case 'K':
830 /* clear to eol */
831 y1 = (s->y_base + s->y) % s->total_height;
832 for(x = s->x; x < s->width; x++) {
833 c = &s->cells[y1 * s->width + x];
834 c->ch = ' ';
6d6f7c28 835 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
836 c++;
837 update_xy(s, x, s->y);
838 }
839 break;
840 default:
841 break;
842 }
6d6f7c28 843 console_handle_escape(s);
e7f0ad58
FB
844 break;
845 }
846 }
847}
848
849void console_select(unsigned int index)
850{
851 TextConsole *s;
6d6f7c28 852
e7f0ad58
FB
853 if (index >= MAX_CONSOLES)
854 return;
855 s = consoles[index];
856 if (s) {
857 active_console = s;
858 if (s->text_console) {
859 if (s->g_width != s->ds->width ||
8e3a9fd2 860 s->g_height != s->ds->height) {
6d6f7c28
PB
861 s->g_width = s->ds->width;
862 s->g_height = s->ds->height;
e7f0ad58 863 text_console_resize(s);
95219897 864 }
e7f0ad58 865 console_refresh(s);
95219897
PB
866 } else {
867 vga_hw_invalidate();
e7f0ad58
FB
868 }
869 }
870}
871
872static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
873{
874 TextConsole *s = chr->opaque;
875 int i;
876
877 console_show_cursor(s, 0);
878 for(i = 0; i < len; i++) {
879 console_putchar(s, buf[i]);
880 }
881 console_show_cursor(s, 1);
882 return len;
883}
884
885static void console_chr_add_read_handler(CharDriverState *chr,
886 IOCanRWHandler *fd_can_read,
887 IOReadHandler *fd_read, void *opaque)
888{
889 TextConsole *s = chr->opaque;
e15d7371 890 s->fd_can_read = fd_can_read;
e7f0ad58
FB
891 s->fd_read = fd_read;
892 s->fd_opaque = opaque;
893}
894
6fcfafb7
FB
895static void console_send_event(CharDriverState *chr, int event)
896{
897 TextConsole *s = chr->opaque;
898 int i;
899
900 if (event == CHR_EVENT_FOCUS) {
901 for(i = 0; i < nb_consoles; i++) {
902 if (consoles[i] == s) {
903 console_select(i);
904 break;
905 }
906 }
907 }
908}
909
e15d7371
FB
910static void kbd_send_chars(void *opaque)
911{
912 TextConsole *s = opaque;
913 int len;
914 uint8_t buf[16];
915
916 len = s->fd_can_read(s->fd_opaque);
917 if (len > s->out_fifo.count)
918 len = s->out_fifo.count;
919 if (len > 0) {
920 if (len > sizeof(buf))
921 len = sizeof(buf);
922 qemu_fifo_read(&s->out_fifo, buf, len);
923 s->fd_read(s->fd_opaque, buf, len);
924 }
925 /* characters are pending: we send them a bit later (XXX:
926 horrible, should change char device API) */
927 if (s->out_fifo.count > 0) {
928 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
929 }
930}
931
e7f0ad58
FB
932/* called when an ascii key is pressed */
933void kbd_put_keysym(int keysym)
934{
935 TextConsole *s;
936 uint8_t buf[16], *q;
937 int c;
938
939 s = active_console;
940 if (!s || !s->text_console)
941 return;
942
943 switch(keysym) {
944 case QEMU_KEY_CTRL_UP:
945 console_scroll(-1);
946 break;
947 case QEMU_KEY_CTRL_DOWN:
948 console_scroll(1);
949 break;
950 case QEMU_KEY_CTRL_PAGEUP:
951 console_scroll(-10);
952 break;
953 case QEMU_KEY_CTRL_PAGEDOWN:
954 console_scroll(10);
955 break;
956 default:
e15d7371
FB
957 /* convert the QEMU keysym to VT100 key string */
958 q = buf;
959 if (keysym >= 0xe100 && keysym <= 0xe11f) {
960 *q++ = '\033';
961 *q++ = '[';
962 c = keysym - 0xe100;
963 if (c >= 10)
964 *q++ = '0' + (c / 10);
965 *q++ = '0' + (c % 10);
966 *q++ = '~';
967 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
968 *q++ = '\033';
969 *q++ = '[';
970 *q++ = keysym & 0xff;
971 } else {
e7f0ad58 972 *q++ = keysym;
e15d7371
FB
973 }
974 if (s->fd_read) {
975 qemu_fifo_write(&s->out_fifo, buf, q - buf);
976 kbd_send_chars(s);
e7f0ad58
FB
977 }
978 break;
979 }
980}
981
95219897 982static TextConsole *new_console(DisplayState *ds, int text)
e7f0ad58
FB
983{
984 TextConsole *s;
95219897 985 int i;
e7f0ad58
FB
986
987 if (nb_consoles >= MAX_CONSOLES)
988 return NULL;
989 s = qemu_mallocz(sizeof(TextConsole));
990 if (!s) {
991 return NULL;
992 }
95219897 993 if (!active_console || (active_console->text_console && !text))
e7f0ad58
FB
994 active_console = s;
995 s->ds = ds;
95219897
PB
996 s->text_console = text;
997 if (text) {
998 consoles[nb_consoles++] = s;
999 } else {
1000 /* HACK: Put graphical consoles before text consoles. */
1001 for (i = nb_consoles; i > 0; i--) {
1002 if (!consoles[i - 1]->text_console)
1003 break;
1004 consoles[i] = consoles[i - 1];
1005 }
1006 consoles[i] = s;
1007 }
1008 return s;
1009}
1010
1011TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1012 vga_hw_invalidate_ptr invalidate,
1013 vga_hw_screen_dump_ptr screen_dump,
1014 void *opaque)
1015{
1016 TextConsole *s;
1017
1018 s = new_console(ds, 0);
1019 if (!s)
1020 return NULL;
1021 s->hw_update = update;
1022 s->hw_invalidate = invalidate;
1023 s->hw_screen_dump = screen_dump;
1024 s->hw = opaque;
e7f0ad58
FB
1025 return s;
1026}
1027
95219897 1028int is_graphic_console(void)
e7f0ad58 1029{
95219897 1030 return !active_console->text_console;
e7f0ad58
FB
1031}
1032
1033CharDriverState *text_console_init(DisplayState *ds)
1034{
1035 CharDriverState *chr;
1036 TextConsole *s;
6d6f7c28 1037 int i,j;
e7f0ad58 1038 static int color_inited;
6d6f7c28 1039
e7f0ad58
FB
1040 chr = qemu_mallocz(sizeof(CharDriverState));
1041 if (!chr)
1042 return NULL;
95219897 1043 s = new_console(ds, 1);
e7f0ad58
FB
1044 if (!s) {
1045 free(chr);
1046 return NULL;
1047 }
e7f0ad58
FB
1048 chr->opaque = s;
1049 chr->chr_write = console_puts;
1050 chr->chr_add_read_handler = console_chr_add_read_handler;
6fcfafb7
FB
1051 chr->chr_send_event = console_send_event;
1052
e15d7371
FB
1053 s->out_fifo.buf = s->out_fifo_buf;
1054 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1055 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1056
e7f0ad58
FB
1057 if (!color_inited) {
1058 color_inited = 1;
6d6f7c28
PB
1059 for(j = 0; j < 2; j++) {
1060 for(i = 0; i < 8; i++) {
1061 color_table[j][i] = col_expand(s->ds,
1062 vga_get_color(s->ds, color_table_rgb[j][i]));
1063 }
e7f0ad58
FB
1064 }
1065 }
1066 s->y_displayed = 0;
1067 s->y_base = 0;
1068 s->total_height = DEFAULT_BACKSCROLL;
1069 s->x = 0;
1070 s->y = 0;
e7f0ad58
FB
1071 s->g_width = s->ds->width;
1072 s->g_height = s->ds->height;
6d6f7c28
PB
1073
1074 /* Set text attribute defaults */
1075 s->t_attrib_default.bold = 0;
1076 s->t_attrib_default.uline = 0;
1077 s->t_attrib_default.blink = 0;
1078 s->t_attrib_default.invers = 0;
1079 s->t_attrib_default.unvisible = 0;
1080 s->t_attrib_default.fgcol = COLOR_WHITE;
1081 s->t_attrib_default.bgcol = COLOR_BLACK;
1082
1083 /* set current text attributes to default */
1084 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1085 text_console_resize(s);
1086
1087 return chr;
1088}