source: trunk/packages/xen-3.1/xen-3.1/tools/ioemu/console.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 29.2 KB
Line 
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
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
43typedef struct TextCell {
44    uint8_t ch;
45    TextAttributes t_attrib;
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
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
107/* ??? This is mis-named.
108   It is used for both text and graphical consoles.  */
109struct 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
144static TextConsole *active_console;
145static TextConsole *consoles[MAX_CONSOLES];
146static int nb_consoles = 0;
147
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
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
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 */
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
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}
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
403
404static 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
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 = ' ';
504            c->t_attrib = s->t_attrib_default;
505            c++;
506        }
507    }
508    qemu_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, 
525                          &(c->t_attrib));
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) {
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
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,
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
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->y++;
623    if (s->y >= s->height) {
624        s->y = s->height - 1;
625
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 = ' ';
638            c->t_attrib = s->t_attrib_default;
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, 
647                          color_table[0][s->t_attrib_default.bgcol]);
648            dpy_update(s->ds, 0, 0, 
649                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
650        }
651    }
652}
653
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
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) {
763        case '\r'/* carriage return */
764            s->x = 0;
765            break;
766        case '\n'/* newline */
767            console_put_lf(s);
768            break;
769        case '\b'/* backspace */
770            if (s->x > 0) 
771                s->x--;
772            break;
773        case '\t'/* tabspace */
774            if (s->x + (8 - (s->x % 8)) > s->width) {
775                s->x = 0;
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                s->x = 0;
796                console_put_lf(s);
797            }
798            break;
799        }
800        break;
801    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
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;
811    case TTY_STATE_CSI: /* handle escape sequence parameters */
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 = ' ';
837                    c->t_attrib = s->t_attrib_default;
838                    c++;
839                    update_xy(s, x, s->y);
840                }
841                break;
842            default:
843                break;
844            }
845            console_handle_escape(s);
846            break;
847        }
848    }
849}
850
851void console_select(unsigned int index)
852{
853    TextConsole *s;
854
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 ||
862                s->g_height != s->ds->height) {
863                s->g_width = s->ds->width;
864                s->g_height = s->ds->height;
865                text_console_resize(s);
866            }
867            console_refresh(s);
868        } else {
869            vga_hw_invalidate();
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;
892    s->fd_can_read = fd_can_read;
893    s->fd_read = fd_read;
894    s->fd_opaque = opaque;
895}
896
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
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
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:
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 {
974                *q++ = keysym;
975        }
976        if (s->fd_read) {
977            qemu_fifo_write(&s->out_fifo, buf, q - buf);
978            kbd_send_chars(s);
979        }
980        break;
981    }
982}
983
984static TextConsole *new_console(DisplayState *ds, int text)
985{
986    TextConsole *s;
987    int i;
988
989    if (nb_consoles >= MAX_CONSOLES)
990        return NULL;
991    s = qemu_mallocz(sizeof(TextConsole));
992    if (!s) {
993        return NULL;
994    }
995    if (!active_console || (active_console->text_console && !text))
996        active_console = s;
997    s->ds = ds;
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;
1027    return s;
1028}
1029
1030int is_graphic_console(void)
1031{
1032    return !active_console->text_console;
1033}
1034
1035void set_color_table(DisplayState *ds) 
1036{
1037    int i, j;
1038    for(j = 0; j < 2; j++) {
1039        for(i = 0; i < 8; i++) {
1040            color_table[j][i] =
1041                col_expand(ds, vga_get_color(ds, color_table_rgb[j][i]));
1042        }
1043    }
1044}
1045
1046CharDriverState *text_console_init(DisplayState *ds)
1047{
1048    CharDriverState *chr;
1049    TextConsole *s;
1050    static int color_inited;
1051
1052    chr = qemu_mallocz(sizeof(CharDriverState));
1053    if (!chr)
1054        return NULL;
1055    s = new_console(ds, 1);
1056    if (!s) {
1057        free(chr);
1058        return NULL;
1059    }
1060    chr->opaque = s;
1061    chr->chr_write = console_puts;
1062    chr->chr_add_read_handler = console_chr_add_read_handler;
1063    chr->chr_send_event = console_send_event;
1064
1065    s->out_fifo.buf = s->out_fifo_buf;
1066    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1067    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1068   
1069    if (!color_inited) {
1070        color_inited = 1;
1071        set_color_table(ds);
1072    }
1073    s->y_displayed = 0;
1074    s->y_base = 0;
1075    s->total_height = DEFAULT_BACKSCROLL;
1076    s->x = 0;
1077    s->y = 0;
1078    s->g_width = s->ds->width;
1079    s->g_height = s->ds->height;
1080
1081    /* Set text attribute defaults */
1082    s->t_attrib_default.bold = 0;
1083    s->t_attrib_default.uline = 0;
1084    s->t_attrib_default.blink = 0;
1085    s->t_attrib_default.invers = 0;
1086    s->t_attrib_default.unvisible = 0;
1087    s->t_attrib_default.fgcol = COLOR_WHITE;
1088    s->t_attrib_default.bgcol = COLOR_BLACK;
1089
1090    /* set current text attributes to default */
1091    s->t_attrib = s->t_attrib_default;
1092    text_console_resize(s);
1093
1094    return chr;
1095}
Note: See TracBrowser for help on using the repository browser.