]> git.proxmox.com Git - qemu.git/blob - console.c
avoid name conflicts
[qemu.git] / console.c
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
26 //#define DEBUG_CONSOLE
27 #define DEFAULT_BACKSCROLL 512
28 #define MAX_CONSOLES 12
29
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)
32
33 typedef 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
43 typedef struct TextCell {
44 uint8_t ch;
45 TextAttributes t_attrib;
46 } TextCell;
47
48 #define MAX_ESC_PARAMS 3
49
50 enum TTYState {
51 TTY_STATE_NORM,
52 TTY_STATE_ESC,
53 TTY_STATE_CSI,
54 };
55
56 typedef struct QEMUFIFO {
57 uint8_t *buf;
58 int buf_size;
59 int count, wptr, rptr;
60 } QEMUFIFO;
61
62 int 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
85 int 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
107 /* ??? This is mis-named.
108 It is used for both text and graphical consoles. */
109 struct TextConsole {
110 int text_console; /* true if text console */
111 DisplayState *ds;
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
118 int g_width, g_height;
119 int width;
120 int height;
121 int total_height;
122 int backscroll_height;
123 int x, y;
124 int y_displayed;
125 int y_base;
126 TextAttributes t_attrib_default; /* default text attributes */
127 TextAttributes t_attrib; /* currently active text attributes */
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 */
135 IOCanRWHandler *fd_can_read;
136 IOReadHandler *fd_read;
137 void *fd_opaque;
138 /* fifo for key pressed */
139 QEMUFIFO out_fifo;
140 uint8_t out_fifo_buf[16];
141 QEMUTimer *kbd_timer;
142 };
143
144 static TextConsole *active_console;
145 static TextConsole *consoles[MAX_CONSOLES];
146 static int nb_consoles = 0;
147
148 void vga_hw_update(void)
149 {
150 if (active_console->hw_update)
151 active_console->hw_update(active_console->hw);
152 }
153
154 void vga_hw_invalidate(void)
155 {
156 if (active_console->hw_invalidate)
157 active_console->hw_invalidate(active_console->hw);
158 }
159
160 void 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
168 /* convert a RGBA color to a color index usable in graphic primitives */
169 static 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
204 static 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) */
240 static 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
292 static 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
311 static const uint32_t dmask4[4] = {
312 PAT(0x00000000),
313 PAT(0x0000ffff),
314 PAT(0xffff0000),
315 PAT(0xffffffff),
316 };
317
318 static uint32_t color_table[2][8];
319
320 enum 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
331 static const uint32_t color_table_rgb[2][8] = {
332 { /* dark */
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 */
341 },
342 { /* bright */
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 */
351 }
352 };
353
354 static 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 }
371 #ifdef DEBUG_CONSOLE
372 static 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
403
404 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
405 TextAttributes *t_attrib)
406 {
407 uint8_t *d;
408 const uint8_t *font_ptr;
409 unsigned int font_data, linesize, xorcol, bpp;
410 int i;
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 }
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++;
436 if (t_attrib->uline
437 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
438 font_data = 0xFFFF;
439 }
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++;
449 if (t_attrib->uline
450 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
451 font_data = 0xFFFF;
452 }
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++;
463 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
464 font_data = 0xFFFF;
465 }
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
480 static 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 = ' ';
504 c->t_attrib = s->t_attrib_default;
505 c++;
506 }
507 }
508 free(s->cells);
509 s->cells = cells;
510 }
511
512 static 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,
525 &(c->t_attrib));
526 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
527 FONT_WIDTH, FONT_HEIGHT);
528 }
529 }
530 }
531
532 static 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) {
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);
548 } else {
549 vga_putcharxy(s->ds, s->x, y, c->ch,
550 &(c->t_attrib));
551 }
552 dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
553 FONT_WIDTH, FONT_HEIGHT);
554 }
555 }
556 }
557
558 static 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,
567 color_table[0][COLOR_BLACK]);
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,
573 &(c->t_attrib));
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
583 static 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
617 static 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;
626
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 = ' ';
639 c->t_attrib = s->t_attrib_default;
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,
648 color_table[0][s->t_attrib_default.bgcol]);
649 dpy_update(s->ds, 0, 0,
650 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
651 }
652 }
653 }
654
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 */
659 static 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
756 static 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) {
764 case '\r': /* carriage return */
765 s->x = 0;
766 break;
767 case '\n': /* newline */
768 console_put_lf(s);
769 break;
770 case '\b': /* backspace */
771 if (s->x > 0)
772 s->x--;
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) */
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;
791 c->t_attrib = s->t_attrib;
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;
799 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
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;
809 case TTY_STATE_CSI: /* handle escape sequence parameters */
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 = ' ';
835 c->t_attrib = s->t_attrib_default;
836 c++;
837 update_xy(s, x, s->y);
838 }
839 break;
840 default:
841 break;
842 }
843 console_handle_escape(s);
844 break;
845 }
846 }
847 }
848
849 void console_select(unsigned int index)
850 {
851 TextConsole *s;
852
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 ||
860 s->g_height != s->ds->height) {
861 s->g_width = s->ds->width;
862 s->g_height = s->ds->height;
863 text_console_resize(s);
864 }
865 console_refresh(s);
866 } else {
867 vga_hw_invalidate();
868 }
869 }
870 }
871
872 static 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
885 static 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;
890 s->fd_can_read = fd_can_read;
891 s->fd_read = fd_read;
892 s->fd_opaque = opaque;
893 }
894
895 static 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
910 static 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
932 /* called when an ascii key is pressed */
933 void 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:
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 {
972 *q++ = keysym;
973 }
974 if (s->fd_read) {
975 qemu_fifo_write(&s->out_fifo, buf, q - buf);
976 kbd_send_chars(s);
977 }
978 break;
979 }
980 }
981
982 static TextConsole *new_console(DisplayState *ds, int text)
983 {
984 TextConsole *s;
985 int i;
986
987 if (nb_consoles >= MAX_CONSOLES)
988 return NULL;
989 s = qemu_mallocz(sizeof(TextConsole));
990 if (!s) {
991 return NULL;
992 }
993 if (!active_console || (active_console->text_console && !text))
994 active_console = s;
995 s->ds = ds;
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
1011 TextConsole *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;
1025 return s;
1026 }
1027
1028 int is_graphic_console(void)
1029 {
1030 return !active_console->text_console;
1031 }
1032
1033 CharDriverState *text_console_init(DisplayState *ds)
1034 {
1035 CharDriverState *chr;
1036 TextConsole *s;
1037 int i,j;
1038 static int color_inited;
1039
1040 chr = qemu_mallocz(sizeof(CharDriverState));
1041 if (!chr)
1042 return NULL;
1043 s = new_console(ds, 1);
1044 if (!s) {
1045 free(chr);
1046 return NULL;
1047 }
1048 chr->opaque = s;
1049 chr->chr_write = console_puts;
1050 chr->chr_add_read_handler = console_chr_add_read_handler;
1051 chr->chr_send_event = console_send_event;
1052
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
1057 if (!color_inited) {
1058 color_inited = 1;
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 }
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;
1071 s->g_width = s->ds->width;
1072 s->g_height = s->ds->height;
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;
1085 text_console_resize(s);
1086
1087 return chr;
1088 }