]> git.proxmox.com Git - qemu.git/blame - console.c
fixed movd mmx/sse insn
[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
e7f0ad58
FB
622 s->y++;
623 if (s->y >= s->height) {
624 s->y = s->height - 1;
6d6f7c28 625
e7f0ad58
FB
626 if (s->y_displayed == s->y_base) {
627 if (++s->y_displayed == s->total_height)
628 s->y_displayed = 0;
629 }
630 if (++s->y_base == s->total_height)
631 s->y_base = 0;
632 if (s->backscroll_height < s->total_height)
633 s->backscroll_height++;
634 y1 = (s->y_base + s->height - 1) % s->total_height;
635 c = &s->cells[y1 * s->width];
636 for(x = 0; x < s->width; x++) {
637 c->ch = ' ';
6d6f7c28 638 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
639 c++;
640 }
641 if (s == active_console && s->y_displayed == s->y_base) {
642 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
643 s->width * FONT_WIDTH,
644 (s->height - 1) * FONT_HEIGHT);
645 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
646 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 647 color_table[0][s->t_attrib_default.bgcol]);
e7f0ad58
FB
648 dpy_update(s->ds, 0, 0,
649 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
650 }
651 }
652}
653
6d6f7c28
PB
654/* Set console attributes depending on the current escape codes.
655 * NOTE: I know this code is not very efficient (checking every color for it
656 * self) but it is more readable and better maintainable.
657 */
658static void console_handle_escape(TextConsole *s)
659{
660 int i;
661
662 if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
663 s->t_attrib = s->t_attrib_default;
664 return;
665 }
666 for (i=0; i<s->nb_esc_params; i++) {
667 switch (s->esc_params[i]) {
668 case 0: /* reset all console attributes to default */
669 s->t_attrib = s->t_attrib_default;
670 break;
671 case 1:
672 s->t_attrib.bold = 1;
673 break;
674 case 4:
675 s->t_attrib.uline = 1;
676 break;
677 case 5:
678 s->t_attrib.blink = 1;
679 break;
680 case 7:
681 s->t_attrib.invers = 1;
682 break;
683 case 8:
684 s->t_attrib.unvisible = 1;
685 break;
686 case 22:
687 s->t_attrib.bold = 0;
688 break;
689 case 24:
690 s->t_attrib.uline = 0;
691 break;
692 case 25:
693 s->t_attrib.blink = 0;
694 break;
695 case 27:
696 s->t_attrib.invers = 0;
697 break;
698 case 28:
699 s->t_attrib.unvisible = 0;
700 break;
701 /* set foreground color */
702 case 30:
703 s->t_attrib.fgcol=COLOR_BLACK;
704 break;
705 case 31:
706 s->t_attrib.fgcol=COLOR_RED;
707 break;
708 case 32:
709 s->t_attrib.fgcol=COLOR_GREEN;
710 break;
711 case 33:
712 s->t_attrib.fgcol=COLOR_YELLOW;
713 break;
714 case 34:
715 s->t_attrib.fgcol=COLOR_BLUE;
716 break;
717 case 35:
718 s->t_attrib.fgcol=COLOR_MAGENTA;
719 break;
720 case 36:
721 s->t_attrib.fgcol=COLOR_CYAN;
722 break;
723 case 37:
724 s->t_attrib.fgcol=COLOR_WHITE;
725 break;
726 /* set background color */
727 case 40:
728 s->t_attrib.bgcol=COLOR_BLACK;
729 break;
730 case 41:
731 s->t_attrib.bgcol=COLOR_RED;
732 break;
733 case 42:
734 s->t_attrib.bgcol=COLOR_GREEN;
735 break;
736 case 43:
737 s->t_attrib.bgcol=COLOR_YELLOW;
738 break;
739 case 44:
740 s->t_attrib.bgcol=COLOR_BLUE;
741 break;
742 case 45:
743 s->t_attrib.bgcol=COLOR_MAGENTA;
744 break;
745 case 46:
746 s->t_attrib.bgcol=COLOR_CYAN;
747 break;
748 case 47:
749 s->t_attrib.bgcol=COLOR_WHITE;
750 break;
751 }
752 }
753}
754
e7f0ad58
FB
755static void console_putchar(TextConsole *s, int ch)
756{
757 TextCell *c;
758 int y1, i, x;
759
760 switch(s->state) {
761 case TTY_STATE_NORM:
762 switch(ch) {
6d6f7c28 763 case '\r': /* carriage return */
e7f0ad58
FB
764 s->x = 0;
765 break;
6d6f7c28 766 case '\n': /* newline */
e7f0ad58
FB
767 console_put_lf(s);
768 break;
6d6f7c28 769 case '\b': /* backspace */
e15d7371
FB
770 if (s->x > 0)
771 s->x--;
6d6f7c28
PB
772 break;
773 case '\t': /* tabspace */
774 if (s->x + (8 - (s->x % 8)) > s->width) {
bd468840 775 s->x = 0;
6d6f7c28
PB
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++;
bd468840
FB
794 if (s->x >= s->width) {
795 s->x = 0;
e7f0ad58 796 console_put_lf(s);
bd468840 797 }
e7f0ad58
FB
798 break;
799 }
800 break;
6d6f7c28 801 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
802 if (ch == '[') {
803 for(i=0;i<MAX_ESC_PARAMS;i++)
804 s->esc_params[i] = 0;
805 s->nb_esc_params = 0;
806 s->state = TTY_STATE_CSI;
807 } else {
808 s->state = TTY_STATE_NORM;
809 }
810 break;
6d6f7c28 811 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
812 if (ch >= '0' && ch <= '9') {
813 if (s->nb_esc_params < MAX_ESC_PARAMS) {
814 s->esc_params[s->nb_esc_params] =
815 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
816 }
817 } else {
818 s->nb_esc_params++;
819 if (ch == ';')
820 break;
821 s->state = TTY_STATE_NORM;
822 switch(ch) {
823 case 'D':
824 if (s->x > 0)
825 s->x--;
826 break;
827 case 'C':
828 if (s->x < (s->width - 1))
829 s->x++;
830 break;
831 case 'K':
832 /* clear to eol */
833 y1 = (s->y_base + s->y) % s->total_height;
834 for(x = s->x; x < s->width; x++) {
835 c = &s->cells[y1 * s->width + x];
836 c->ch = ' ';
6d6f7c28 837 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
838 c++;
839 update_xy(s, x, s->y);
840 }
841 break;
842 default:
843 break;
844 }
6d6f7c28 845 console_handle_escape(s);
e7f0ad58
FB
846 break;
847 }
848 }
849}
850
851void console_select(unsigned int index)
852{
853 TextConsole *s;
6d6f7c28 854
e7f0ad58
FB
855 if (index >= MAX_CONSOLES)
856 return;
857 s = consoles[index];
858 if (s) {
859 active_console = s;
860 if (s->text_console) {
861 if (s->g_width != s->ds->width ||
8e3a9fd2 862 s->g_height != s->ds->height) {
6d6f7c28
PB
863 s->g_width = s->ds->width;
864 s->g_height = s->ds->height;
e7f0ad58 865 text_console_resize(s);
95219897 866 }
e7f0ad58 867 console_refresh(s);
95219897
PB
868 } else {
869 vga_hw_invalidate();
e7f0ad58
FB
870 }
871 }
872}
873
874static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
875{
876 TextConsole *s = chr->opaque;
877 int i;
878
879 console_show_cursor(s, 0);
880 for(i = 0; i < len; i++) {
881 console_putchar(s, buf[i]);
882 }
883 console_show_cursor(s, 1);
884 return len;
885}
886
887static void console_chr_add_read_handler(CharDriverState *chr,
888 IOCanRWHandler *fd_can_read,
889 IOReadHandler *fd_read, void *opaque)
890{
891 TextConsole *s = chr->opaque;
e15d7371 892 s->fd_can_read = fd_can_read;
e7f0ad58
FB
893 s->fd_read = fd_read;
894 s->fd_opaque = opaque;
895}
896
6fcfafb7
FB
897static void console_send_event(CharDriverState *chr, int event)
898{
899 TextConsole *s = chr->opaque;
900 int i;
901
902 if (event == CHR_EVENT_FOCUS) {
903 for(i = 0; i < nb_consoles; i++) {
904 if (consoles[i] == s) {
905 console_select(i);
906 break;
907 }
908 }
909 }
910}
911
e15d7371
FB
912static void kbd_send_chars(void *opaque)
913{
914 TextConsole *s = opaque;
915 int len;
916 uint8_t buf[16];
917
918 len = s->fd_can_read(s->fd_opaque);
919 if (len > s->out_fifo.count)
920 len = s->out_fifo.count;
921 if (len > 0) {
922 if (len > sizeof(buf))
923 len = sizeof(buf);
924 qemu_fifo_read(&s->out_fifo, buf, len);
925 s->fd_read(s->fd_opaque, buf, len);
926 }
927 /* characters are pending: we send them a bit later (XXX:
928 horrible, should change char device API) */
929 if (s->out_fifo.count > 0) {
930 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
931 }
932}
933
e7f0ad58
FB
934/* called when an ascii key is pressed */
935void kbd_put_keysym(int keysym)
936{
937 TextConsole *s;
938 uint8_t buf[16], *q;
939 int c;
940
941 s = active_console;
942 if (!s || !s->text_console)
943 return;
944
945 switch(keysym) {
946 case QEMU_KEY_CTRL_UP:
947 console_scroll(-1);
948 break;
949 case QEMU_KEY_CTRL_DOWN:
950 console_scroll(1);
951 break;
952 case QEMU_KEY_CTRL_PAGEUP:
953 console_scroll(-10);
954 break;
955 case QEMU_KEY_CTRL_PAGEDOWN:
956 console_scroll(10);
957 break;
958 default:
e15d7371
FB
959 /* convert the QEMU keysym to VT100 key string */
960 q = buf;
961 if (keysym >= 0xe100 && keysym <= 0xe11f) {
962 *q++ = '\033';
963 *q++ = '[';
964 c = keysym - 0xe100;
965 if (c >= 10)
966 *q++ = '0' + (c / 10);
967 *q++ = '0' + (c % 10);
968 *q++ = '~';
969 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
970 *q++ = '\033';
971 *q++ = '[';
972 *q++ = keysym & 0xff;
973 } else {
e7f0ad58 974 *q++ = keysym;
e15d7371
FB
975 }
976 if (s->fd_read) {
977 qemu_fifo_write(&s->out_fifo, buf, q - buf);
978 kbd_send_chars(s);
e7f0ad58
FB
979 }
980 break;
981 }
982}
983
95219897 984static TextConsole *new_console(DisplayState *ds, int text)
e7f0ad58
FB
985{
986 TextConsole *s;
95219897 987 int i;
e7f0ad58
FB
988
989 if (nb_consoles >= MAX_CONSOLES)
990 return NULL;
991 s = qemu_mallocz(sizeof(TextConsole));
992 if (!s) {
993 return NULL;
994 }
95219897 995 if (!active_console || (active_console->text_console && !text))
e7f0ad58
FB
996 active_console = s;
997 s->ds = ds;
95219897
PB
998 s->text_console = text;
999 if (text) {
1000 consoles[nb_consoles++] = s;
1001 } else {
1002 /* HACK: Put graphical consoles before text consoles. */
1003 for (i = nb_consoles; i > 0; i--) {
1004 if (!consoles[i - 1]->text_console)
1005 break;
1006 consoles[i] = consoles[i - 1];
1007 }
1008 consoles[i] = s;
1009 }
1010 return s;
1011}
1012
1013TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1014 vga_hw_invalidate_ptr invalidate,
1015 vga_hw_screen_dump_ptr screen_dump,
1016 void *opaque)
1017{
1018 TextConsole *s;
1019
1020 s = new_console(ds, 0);
1021 if (!s)
1022 return NULL;
1023 s->hw_update = update;
1024 s->hw_invalidate = invalidate;
1025 s->hw_screen_dump = screen_dump;
1026 s->hw = opaque;
e7f0ad58
FB
1027 return s;
1028}
1029
95219897 1030int is_graphic_console(void)
e7f0ad58 1031{
95219897 1032 return !active_console->text_console;
e7f0ad58
FB
1033}
1034
1035CharDriverState *text_console_init(DisplayState *ds)
1036{
1037 CharDriverState *chr;
1038 TextConsole *s;
6d6f7c28 1039 int i,j;
e7f0ad58 1040 static int color_inited;
6d6f7c28 1041
e7f0ad58
FB
1042 chr = qemu_mallocz(sizeof(CharDriverState));
1043 if (!chr)
1044 return NULL;
95219897 1045 s = new_console(ds, 1);
e7f0ad58
FB
1046 if (!s) {
1047 free(chr);
1048 return NULL;
1049 }
e7f0ad58
FB
1050 chr->opaque = s;
1051 chr->chr_write = console_puts;
1052 chr->chr_add_read_handler = console_chr_add_read_handler;
6fcfafb7
FB
1053 chr->chr_send_event = console_send_event;
1054
e15d7371
FB
1055 s->out_fifo.buf = s->out_fifo_buf;
1056 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1057 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1058
e7f0ad58
FB
1059 if (!color_inited) {
1060 color_inited = 1;
6d6f7c28
PB
1061 for(j = 0; j < 2; j++) {
1062 for(i = 0; i < 8; i++) {
1063 color_table[j][i] = col_expand(s->ds,
1064 vga_get_color(s->ds, color_table_rgb[j][i]));
1065 }
e7f0ad58
FB
1066 }
1067 }
1068 s->y_displayed = 0;
1069 s->y_base = 0;
1070 s->total_height = DEFAULT_BACKSCROLL;
1071 s->x = 0;
1072 s->y = 0;
e7f0ad58
FB
1073 s->g_width = s->ds->width;
1074 s->g_height = s->ds->height;
6d6f7c28
PB
1075
1076 /* Set text attribute defaults */
1077 s->t_attrib_default.bold = 0;
1078 s->t_attrib_default.uline = 0;
1079 s->t_attrib_default.blink = 0;
1080 s->t_attrib_default.invers = 0;
1081 s->t_attrib_default.unvisible = 0;
1082 s->t_attrib_default.fgcol = COLOR_WHITE;
1083 s->t_attrib_default.bgcol = COLOR_BLACK;
1084
1085 /* set current text attributes to default */
1086 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1087 text_console_resize(s);
1088
86e94dea
TS
1089 qemu_chr_reset(chr);
1090
e7f0ad58
FB
1091 return chr;
1092}